Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> blindScope, merging);
}
private FlowScope caseEquality(Node left, Node right, FlowScope blindScope,
Function<TypePair, TypePair> merging) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftType = left.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, condition);
}
// restricting left type
JSType restrictedLeftType = (leftType == null) ? null :
leftType.getRestrictedTypeGivenToBooleanOutcome(condition);
if (restrictedLeftType == null) {
return firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
left, blindScope, condition);
rightScope = firstPreciserScopeKnowingConditionOutcome(
right, rightScope, !condition);
StaticSlot<JSType> rightVar = rightScope.findUniqueRefinedSlot(blindScope);
if (rightVar == null || !leftVar.getName().equals(rightVar.getName())) {
return blindScope;
}
JSType type = leftVar.getType().getLeastSupertype(rightVar.getType());
FlowScope informed = blindScope.createChildFlowScope();
informed.inferSlotType(leftVar.getName(), type);
return informed;
}
if (leftType == null) {
return blindScope;
}
JSType rightType = right.getJSType();
ObjectType targetType =
typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
if (rightType != null && rightType.isFunctionType()) {
targetType = rightType.toMaybeFunctionType();
}
Visitor<JSType> visitor;
if (outcome) {
visitor = new RestrictByTrueInstanceOfResultVisitor(targetType);
} else {
visitor = new RestrictByFalseInstanceOfResultVisitor(targetType);
}
return maybeRestrictName(
blindScope, left, leftType, leftType.visit(visitor));
}
/**
* Given 'property in object', ensures that the object has the property in the
* informed scope by defining it as a qualified name
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> if the object type lacks
* the property and it's not in the blind scope.
* @param object The node of the right-side of the in.
* @param propertyName The string of the left-side of the in.
*/
private FlowScope caseIn(Node object, String propertyName, FlowScope blindScope) {
JSType jsType = object.getJSType();
jsType = this.getRestrictedWithoutNull(jsType);
jsType = this.getRestrictedWithoutUndefined(jsType);
boolean hasProperty = false;
ObjectType objectType = ObjectType.cast(jsType);
if (objectType != null) {
hasProperty = objectType.hasProperty(propertyName);
}
if (!hasProperty) {
String qualifiedName = object.getQualifiedName();
if (qualifiedName != null) {
String propertyQualifiedName = qualifiedName + "." + propertyName;
if (blindScope.getSlot(propertyQualifiedName) == null) {
FlowScope informed = blindScope.createChildFlowScope();
JSType unknownType = typeRegistry.getNativeType(
JSTypeNative.UNKNOWN_TYPE);
informed.inferQualifiedSlot(
object, propertyQualifiedName, unknownType, unknownType);
return informed;
}
}
}
return blindScope;
}
/**
* @see SemanticReverseAbstractInterpreter#caseInstanceOf
*/
private class RestrictByTrueInstanceOfResultVisitor
extends RestrictByTrueTypeOfResultVisitor {
private final ObjectType target;
RestrictByTrueInstanceOfResultVisitor(ObjectType target) {
this.target = target;
}
@Override
protected JSType caseTopType(JSType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseUnknownType() {
FunctionType funcTarget = JSType.toMaybeFunctionType(target);
if (funcTarget != null && funcTarget.hasInstanceType()) {
return funcTarget.getInstanceType();
}
return getNativeType(UNKNOWN_TYPE);
}
@Override
public JSType caseObjectType(ObjectType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseUnionType(UnionType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseFunctionType(FunctionType type) {
return caseObjectType(type);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> ∧ Object} = {@code Any}</li>
* <li>{@code Number ∧ Object} = {@code Number}</li>
* </ul>
* @return {@code this ∨ that}
*/
public JSType getGreatestSubtype(JSType that) {
return getGreatestSubtype(this, that);
}
/**
* A generic implementation meant to be used as a helper for common
* getGreatestSubtype implementations.
*/
static JSType getGreatestSubtype(JSType thisType, JSType thatType) {
if (thisType.isFunctionType() && thatType.isFunctionType()) {
// The FunctionType sub-lattice is not well-defined. i.e., the
// proposition
// A < B => sup(A, B) == B
// does not hold because of unknown parameters and return types.
// See the comment in supAndInfHelper for more info on this.
return thisType.toMaybeFunctionType().supAndInfHelper(
thatType.toMaybeFunctionType(), false);
} else if (thisType.isEquivalentTo(thatType)) {
return thisType;
} else if (thisType.isUnknownType() || thatType.isUnknownType()) {
// The greatest subtype with any unknown type is the universal
// unknown type, unless the two types are equal.
return thisType.isEquivalentTo(thatType) ? thisType :
thisType.getNativeType(JSTypeNative.UNKNOWN_TYPE);
} else if (thisType.isSubtype(thatType)) {
return filterNoResolvedType(thisType);
} else if (thatType.isSubtype(thisType)) {
return filterNoResolvedType(thatType);
} else if (thisType.isUnionType()) {
return thisType.toMaybeUnionType().meet(thatType);
} else if (thatType.isUnionType()) {
return thatType.toMaybeUnionType().meet(thisType);
} else if (thisType.isRecordType()) {
return thisType.toMaybeRecordType().getGreatestSubtypeHelper(thatType);
} else if (thatType.isRecordType()) {
return thatType.toMaybeRecordType().getGreatestSubtypeHelper(thisType);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> T visit(Visitor<T> visitor);
/**
* Force this type to resolve, even if the registry is in a lazy
* resolving mode.
* @see #resolve
*/
public final JSType forceResolve(ErrorReporter t, StaticScope<JSType> scope) {
ResolveMode oldResolveMode = registry.getResolveMode();
registry.setResolveMode(ResolveMode.IMMEDIATE);
JSType result = resolve(t, scope);
registry.setResolveMode(oldResolveMode);
return result;
}
/**
* Resolve this type in the given scope.
*
* The returned value must be equal to {@code this}, as defined by
* {@link #isEquivalentTo}. It may or may not be the same object. This method
* may modify the internal state of {@code this}, as long as it does
* so in a way that preserves Object equality.
*
* For efficiency, we should only resolve a type once per compilation job.
* For incremental compilations, one compilation job may need the
* artifacts from a previous generation, so we will eventually need
* a generational flag instead of a boolean one.
*/
public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) {
if (resolved) {
// TODO(nicksantos): Check to see if resolve() looped back on itself.
// Preconditions.checkNotNull(resolveResult);
if (resolveResult == null) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return resolveResult;
}
resolved = true;
resolveResult = resolveInternal(t, scope);
resolveResult.setResolvedTypeInternal(resolveResult);
return resolveResult;
}
/**
* @see #resolve
*/
abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope);
void setResolvedTypeInternal(JSType type) {
resolveResult = type;
resolved = true;
}
/** Whether the type has been resolved. */
public final boolean isResolved() {
return resolved;
}
/** Clears the resolved field. */
public final void clearResolved() {
resolved = false;
resolveResult = null;
}
/**
* A null-safe resolve.
* @see #resolve
*/
static final JS
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>.isObjectLitKey(n, parent)) {
JSDocInfo info = n.getJSDocInfo();
if (info == null) {
info = parent.getJSDocInfo();
}
allowDupe =
info != null && info.getSuppressions().contains("duplicate");
}
JSType varType = var.getType();
// Only report duplicate declarations that have types. Other duplicates
// will be reported by the syntactic scope creator later in the
// compilation process.
if (varType != null &&
varType != typeRegistry.getNativeType(UNKNOWN_TYPE) &&
newType != null &&
newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) {
// If there are two typed declarations of the same variable, that
// is an error and the second declaration is ignored, except in the
// case of native types. A null input type means that the declaration
// was made in TypedScopeCreator#createInitialScope and is a
// native type. We should redeclare it at the new input site.
if (var.input == null) {
Scope s = var.getScope();
s.undeclare(var);
newVar = s.declare(variableName, n, varType, input, false);
n.setJSType(varType);
if (parent.isVar()) {
if (n.getFirstChild() != null) {
n.getFirstChild().setJSType(varType);
}
} else {
Preconditions.checkState(parent.isFunction());
parent.setJSType(varType);
}
} else {
// Always warn about duplicates if the overridden type does not
// match the original type.
//
// If the types match, suppress the warning iff there was a @suppress
// tag, or if the original declaration was a stub.
if (!(allowDupe ||
var.getParentNode().isExprResult()) ||
!newType.equals(varType)) {
report(JSError.make(sourceName, n, DUP_VAR_DECLARATION,
variableName, newType.toString(), var.getInputName(),
String.valueOf(var.nameNode.getLineno()),
varType.toString()));
}
}
}
return newVar;
}
/**
* Expect that all properties
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> This method gets the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(user): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
private JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
private JSError report(JSError error) {
if (shouldReport) {
compiler.report(error);
}
return error;
}
/**
* Signals that the first type and the second type have been
* used interchangeably.
*
* Type-based optimizations should take this into account
* so that they don't wreck code with type warnings.
*/
static class TypeMismatch {
final JSType typeA;
final JSType typeB;
final JSError src;
/**
* It's the responsibility of the class that creates the
* {@code TypeMismatch} to ensure that {@code a} and {@code b} are
* non-matching types.
*/
TypeMismatch(JSType a, JSType b, JSError src) {
this.typeA = a;
this.typeB = b;
this.src = src;
}
@Override public boolean equals(Object object) {
if (object instanceof TypeMismatch) {
TypeMismatch that = (TypeMismatch) object;
return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB))
|| (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB));
}
return false;
}
@Override public int hashCode() {
return Objects.hashCode(typeA, typeB);
}
@Override public String toString() {
return "(" + typeA + ", " + typeB + ")";
}
}
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
this.name = name;
}
@Override
public String getReferenceName() {
return name;
}
@Override
String toStringHelper(boolean forAnnotations) {
return name;
}
@Override
public TemplateType toMaybeTemplateType() {
return this;
}
@Override
public boolean hasAnyTemplateInternal() {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseTemplateType(this);
}
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> = getNativeType(JSTypeNative.UNKNOWN_TYPE);
name.setJSType(type);
redeclareSimpleVar(scope, name, type);
return scope;
}
private FlowScope traverseAssign(Node n, FlowScope scope) {
Node left = n.getFirstChild();
Node right = n.getLastChild();
scope = traverseChildren(n, scope);
JSType leftType = left.getJSType();
JSType rightType = getJSType(right);
n.setJSType(rightType);
updateScopeForTypeChange(scope, left, leftType, rightType);
return scope;
}
/**
* Updates the scope according to the result of a type change, like
* an assignment or a type cast.
*/
private void updateScopeForTypeChange(
FlowScope scope, Node left, JSType leftType, JSType resultType) {
Preconditions.checkNotNull(resultType);
switch (left.getType()) {
case Token.NAME:
String varName = left.getString();
Var var = syntacticScope.getVar(varName);
// When looking at VAR initializers for declared VARs, we trust
// the declared type over the type it's being initialized to.
// This has two purposes:
// 1) We avoid re-declaring declared variables so that built-in
// types defined in externs are not redeclared.
// 2) When there's a lexical closure like
// /** @type {?string} */ var x = null;
// function f() { x = 'xyz'; }
// the inference will ignore the lexical closure,
// which is just wrong. This bug needs to be fixed eventually.
boolean isVarDeclaration = left.hasChildren();
if (!isVarDeclaration || var == null || var.isTypeInferred()) {
redeclareSimpleVar(scope, left, resultType);
}
left.setJSType(isVarDeclaration || leftType == null ?
resultType : null);
if (var != null && var.isTypeInferred()) {
JSType oldType = var.getType();
var.setType(oldType == null ?
resultType : oldType.getLeastSupertype(resultType));
}
break;
case Token.GETPROP:
String qualifiedName = left.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>getQualifiedName();
if (qualifiedName != null) {
scope.inferQualifiedSlot(left, qualifiedName,
leftType == null ? getNativeType(UNKNOWN_TYPE) : leftType,
resultType);
}
left.setJSType(resultType);
ensurePropertyDefined(left, resultType);
break;
}
}
/**
* Defines a property if the property has not been defined yet.
*/
private void ensurePropertyDefined(Node getprop, JSType rightType) {
String propName = getprop.getLastChild().getString();
JSType nodeType = getJSType(getprop.getFirstChild());
ObjectType objectType = ObjectType.cast(
nodeType.restrictByNotNullOrUndefined());
if (objectType == null) {
registry.registerPropertyOnType(propName, nodeType);
} else {
if (ensurePropertyDeclaredHelper(getprop, objectType)) {
return;
}
if (!objectType.isPropertyTypeDeclared(propName)) {
// We do not want a "stray" assign to define an inferred property
// for every object of this type in the program. So we use a heuristic
// approach to determine whether to infer the property.
//
// 1) If the property is already defined, join it with the previously
// inferred type.
// 2) If this isn't an instance object, define it.
// 3) If the property of an object is being assigned in the constructor,
// define it.
// 4) If this is a stub, define it.
// 5) Otherwise, do not define the type, but declare it in the registry
// so that we can use it for missing property checks.
if (objectType.hasProperty(propName) ||
!objectType.isInstanceType()) {
if ("prototype".equals(propName)) {
objectType.defineDeclaredProperty(
propName, rightType, getprop);
} else {
objectType.defineInferredProperty(
propName, rightType, getprop);
}
} else {
if (getprop.getFirstChild().isThis() &&
getJSType(syntacticScope.getRootNode()).isConstructor()) {
objectType.defineInferredProperty(
propName, rightType, getprop);
} else
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> we have it.
// 1) The var is escaped in a weird way, e.g.,
// function f() { var x = 3; function g() { x = null } (x); }
boolean isInferred = var.isTypeInferred();
boolean unflowable = isInferred &&
isUnflowable(syntacticScope.getVar(varName));
// 2) We're reading type information from another scope for an
// inferred variable.
// var t = null; function f() { (t); }
boolean nonLocalInferredSlot =
isInferred &&
syntacticScope.getParent() != null &&
var == syntacticScope.getParent().getSlot(varName);
if (!unflowable && !nonLocalInferredSlot) {
type = var.getType();
if (type == null) {
type = getNativeType(UNKNOWN_TYPE);
}
}
}
}
n.setJSType(type);
return scope;
}
/** Traverse each element of the array. */
private FlowScope traverseArrayLiteral(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
n.setJSType(getNativeType(ARRAY_TYPE));
return scope;
}
private FlowScope traverseObjectLiteral(Node n, FlowScope scope) {
JSType type = n.getJSType();
Preconditions.checkNotNull(type);
for (Node name = n.getFirstChild(); name != null; name = name.getNext()) {
scope = traverse(name.getFirstChild(), scope);
}
// Object literals can be reflected on other types, or changed with
// type casts.
// See CodingConvention#getObjectLiteralCase and goog.object.reflect.
// Ignore these types of literals.
// TODO(nicksantos): There should be an "anonymous object" type that
// we can check for here.
ObjectType objectType = ObjectType.cast(type);
if (objectType == null) {
return scope;
}
boolean hasLendsName = n.getJSDocInfo() != null &&
n.getJSDocInfo().getLendsName() != null;
if (objectType.hasReferenceName() && !hasLendsName) {
return scope;
}
String qObjName = NodeUtil.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>getBestLValueName(
NodeUtil.getBestLValue(n));
for (Node name = n.getFirstChild(); name != null;
name = name.getNext()) {
Node value = name.getFirstChild();
String memberName = NodeUtil.getObjectLitKeyName(name);
if (memberName != null) {
JSType rawValueType = name.getFirstChild().getJSType();
JSType valueType = NodeUtil.getObjectLitKeyTypeFromValueType(
name, rawValueType);
if (valueType == null) {
valueType = getNativeType(UNKNOWN_TYPE);
}
objectType.defineInferredProperty(memberName, valueType, name);
// Do normal flow inference if this is a direct property assignment.
if (qObjName != null && name.isStringKey()) {
String qKeyName = qObjName + "." + memberName;
Var var = syntacticScope.getVar(qKeyName);
JSType oldType = var == null ? null : var.getType();
if (var != null && var.isTypeInferred()) {
var.setType(oldType == null ?
valueType : oldType.getLeastSupertype(oldType));
}
scope.inferQualifiedSlot(name, qKeyName,
oldType == null ? getNativeType(UNKNOWN_TYPE) : oldType,
valueType);
}
} else {
n.setJSType(getNativeType(UNKNOWN_TYPE));
}
}
return scope;
}
private FlowScope traverseAdd(Node n, FlowScope scope) {
Node left = n.getFirstChild();
Node right = left.getNext();
scope = traverseChildren(n, scope);
JSType leftType = left.getJSType();
JSType rightType = right.getJSType();
JSType type = getNativeType(UNKNOWN_TYPE);
if (leftType != null && rightType != null) {
boolean leftIsUnknown = leftType.isUnknownType();
boolean rightIsUnknown = rightType.isUnknownType();
if (leftIsUnknown && rightIsUnknown) {
type = getNativeType(UNKNOWN_TYPE);
} else if ((!leftIsUnknown && leftType.isString()) ||
(!rightIsUnknown && rightType.isString())) {
type = getNativeType(STRING_TYPE);
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> else if (leftIsUnknown || rightIsUnknown) {
type = getNativeType(UNKNOWN_TYPE);
} else if (isAddedAsNumber(leftType) && isAddedAsNumber(rightType)) {
type = getNativeType(NUMBER_TYPE);
} else {
type = registry.createUnionType(STRING_TYPE, NUMBER_TYPE);
}
}
n.setJSType(type);
if (n.isAssignAdd()) {
updateScopeForTypeChange(scope, left, leftType, type);
}
return scope;
}
private boolean isAddedAsNumber(JSType type) {
return type.isSubtype(registry.createUnionType(VOID_TYPE, NULL_TYPE,
NUMBER_VALUE_OR_OBJECT_TYPE, BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE));
}
private FlowScope traverseHook(Node n, FlowScope scope) {
Node condition = n.getFirstChild();
Node trueNode = condition.getNext();
Node falseNode = n.getLastChild();
// verify the condition
scope = traverse(condition, scope);
// reverse abstract interpret the condition to produce two new scopes
FlowScope trueScope = reverseInterpreter.
getPreciserScopeKnowingConditionOutcome(
condition, scope, true);
FlowScope falseScope = reverseInterpreter.
getPreciserScopeKnowingConditionOutcome(
condition, scope, false);
// traverse the true node with the trueScope
traverse(trueNode, trueScope.createChildFlowScope());
// traverse the false node with the falseScope
traverse(falseNode, falseScope.createChildFlowScope());
// meet true and false nodes' types and assign
JSType trueType = trueNode.getJSType();
JSType falseType = falseNode.getJSType();
if (trueType != null && falseType != null) {
n.setJSType(trueType.getLeastSupertype(falseType));
} else {
n.setJSType(null);
}
return scope.createChildFlowScope();
}
private FlowScope traverseCall(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
Node left = n.getFirstChild();
JSType functionType = getJSType(left).restrictByNotNullOrUndefined();
if (functionType.isFunctionType()) {
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
FunctionType fnType = functionType.toMaybeFunctionType();
n.setJSType(fnType.getReturnType());
backwardsInferenceFromCallSite(n, fnType);
} else if (functionType.equals(getNativeType(CHECKED_UNKNOWN_TYPE))) {
n.setJSType(getNativeType(CHECKED_UNKNOWN_TYPE));
}
scope = tightenTypesAfterAssertions(scope, n);
return scope;
}
private FlowScope tightenTypesAfterAssertions(FlowScope scope,
Node callNode) {
Node left = callNode.getFirstChild();
Node firstParam = left.getNext();
AssertionFunctionSpec assertionFunctionSpec =
assertionFunctionsMap.get(left.getQualifiedName());
if (assertionFunctionSpec == null || firstParam == null) {
return scope;
}
Node assertedNode = assertionFunctionSpec.getAssertedParam(firstParam);
if (assertedNode == null) {
return scope;
}
JSType assertedType = assertionFunctionSpec.getAssertedType(
callNode, registry);
String assertedNodeName = assertedNode.getQualifiedName();
JSType narrowed;
// Handle assertions that enforce expressions evaluate to true.
if (assertedType == null) {
// Handle arbitrary expressions within the assert.
scope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(
assertedNode, scope, true);
// Build the result of the assertExpression
narrowed = getJSType(assertedNode).restrictByNotNullOrUndefined();
} else {
// Handle assertions that enforce expressions are of a certain type.
JSType type = getJSType(assertedNode);
narrowed = type.getGreatestSubtype(assertedType);
if (assertedNodeName != null && type.differsFrom(narrowed)) {
scope = narrowScope(scope, assertedNode, narrowed);
}
}
if (getJSType(callNode).differsFrom(narrowed)) {
callNode.setJSType(narrowed);
}
return scope;
}
private FlowScope narrowScope(FlowScope scope, Node node, JSType narrowed) {
if (node.isThis()) {
// "this" references don't need to be modeled in the control flow graph.
return scope;
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>.hasNext()) {
maybeResolveTemplatedType(
getJSType(declParams.next()),
getJSType(callParams.next()),
resolvedTypes);
}
}
private void resolvedTemplateType(
Map<TemplateType, JSType> map, TemplateType template, JSType resolved) {
JSType previous = map.get(template);
if (!resolved.isUnknownType()) {
if (previous == null) {
map.put(template, resolved);
} else {
JSType join = previous.getLeastSupertype(resolved);
map.put(template, join);
}
}
}
private static class TemplateTypeReplacer extends ModificationVisitor {
private final Map<TemplateType, JSType> replacements;
private final JSTypeRegistry registry;
TemplateTypeReplacer(
JSTypeRegistry registry, Map<TemplateType, JSType> replacements) {
super(registry);
this.registry = registry;
this.replacements = replacements;
}
@Override
public JSType caseTemplateType(TemplateType type) {
JSType replacement = replacements.get(type);
return replacement != null ?
replacement : registry.getNativeType(UNKNOWN_TYPE);
}
}
/**
* For functions with function(this: T, ...) and T as parameters, type
* inference will set the type of this on a function literal argument to the
* the actual type of T.
*/
private boolean inferTemplatedTypesForCall(
Node n, FunctionType fnType) {
if (fnType.getTemplateTypeNames().isEmpty()) {
return false;
}
// Try to infer the template types
Map<TemplateType, JSType> inferred = inferTemplateTypesFromParameters(
fnType, n);
if (inferred.size() > 0) {
// Something useful was found, try to replace it.
TemplateTypeReplacer replacer = new TemplateTypeReplacer(
registry, inferred);
Node callTarget = n.getFirstChild();
FunctionType replacementFnType = fnType.visit(replacer)
.toMaybeFunctionType();
Preconditions.checkNotNull(replacementFnType);
callTarget.setJSType(replacementFnType);
n.setJSType(replacementFnType.getReturnType());
return true;
}
return false;
}
private
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> FlowScope traverseNew(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
Node constructor = n.getFirstChild();
JSType constructorType = constructor.getJSType();
JSType type = null;
if (constructorType != null) {
constructorType = constructorType.restrictByNotNullOrUndefined();
if (constructorType.isUnknownType()) {
type = getNativeType(UNKNOWN_TYPE);
} else {
FunctionType ct = constructorType.toMaybeFunctionType();
if (ct == null && constructorType instanceof FunctionType) {
// If constructorType is a NoObjectType, then toMaybeFunctionType will
// return null. But NoObjectType implements the FunctionType
// interface, precisely because it can validly construct objects.
ct = (FunctionType) constructorType;
}
if (ct != null && ct.isConstructor()) {
type = ct.getInstanceType();
backwardsInferenceFromCallSite(n, ct);
}
}
}
n.setJSType(type);
return scope;
}
private BooleanOutcomePair traverseAnd(Node n, FlowScope scope) {
return traverseShortCircuitingBinOp(n, scope, true);
}
private FlowScope traverseChildren(Node n, FlowScope scope) {
for (Node el = n.getFirstChild(); el != null; el = el.getNext()) {
scope = traverse(el, scope);
}
return scope;
}
private FlowScope traverseGetElem(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
ObjectType objType = ObjectType.cast(
getJSType(n.getFirstChild()).restrictByNotNullOrUndefined());
if (objType != null) {
JSType type = objType.getParameterType();
if (type != null) {
n.setJSType(type);
}
}
return dereferencePointer(n.getFirstChild(), scope);
}
private FlowScope traverseGetProp(Node n, FlowScope scope) {
Node objNode = n.getFirstChild();
Node property = n.getLastChild();
scope = traverseChildren(n, scope);
n.setJSType(
getPropertyType(
objNode.getJSType(), property.getString(), n, scope));
return dereferencePointer(n.getFirstChild(), scope);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
}
/**
* Suppose X is an object with inferred properties.
* Suppose also that X is used in a way where it would only type-check
* correctly if some of those properties are widened.
* Then we should be polite and automatically widen X's properties for him.
*
* For a concrete example, consider:
* param x {{prop: (number|undefined)}}
* function f(x) {}
* f({});
*
* If we give the anonymous object an inferred property of (number|undefined),
* then this code will type-check appropriately.
*/
private void inferPropertyTypesToMatchConstraint(
JSType type, JSType constraint) {
if (type == null || constraint == null) {
return;
}
type.matchConstraint(constraint);
}
/**
* If we access a property of a symbol, then that symbol is not
* null or undefined.
*/
private FlowScope dereferencePointer(Node n, FlowScope scope) {
if (n.isQualifiedName()) {
JSType type = getJSType(n);
JSType narrowed = type.restrictByNotNullOrUndefined();
if (type != narrowed) {
scope = narrowScope(scope, n, narrowed);
}
}
return scope;
}
private JSType getPropertyType(JSType objType, String propName,
Node n, FlowScope scope) {
// We often have a couple of different types to choose from for the
// property. Ordered by accuracy, we have
// 1) A locally inferred qualified name (which is in the FlowScope)
// 2) A globally declared qualified name (which is in the FlowScope)
// 3) A property on the owner type (which is on objType)
// 4) A name in the type registry (as a last resort)
JSType unknownType = getNativeType(UNKNOWN_TYPE);
JSType propertyType = null;
boolean isLocallyInferred = false;
// Scopes sometimes contain inferred type info about qualified names.
String qualifiedName = n.getQualifiedName();
StaticSlot<JSType> var = scope.getSlot(qualifiedName);
if (var != null) {
JSType varType = var.getType();
if (varType != null) {
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
boolean isDeclared = !var.isTypeInferred();
isLocallyInferred = (var != syntacticScope.getSlot(qualifiedName));
if (isDeclared || isLocallyInferred) {
propertyType = varType;
}
}
}
if (propertyType == null && objType != null) {
JSType foundType = objType.findPropertyType(propName);
if (foundType != null) {
propertyType = foundType;
}
}
if ((propertyType == null || propertyType.isUnknownType())
&& qualifiedName != null) {
// If we find this node in the registry, then we can infer its type.
ObjectType regType = ObjectType.cast(registry.getType(qualifiedName));
if (regType != null) {
propertyType = regType.getConstructor();
}
}
if (propertyType == null) {
return getNativeType(UNKNOWN_TYPE);
} else if (propertyType.equals(unknownType) && isLocallyInferred) {
// If the type has been checked in this scope,
// then use CHECKED_UNKNOWN_TYPE instead to indicate that.
return getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
return propertyType;
}
}
private BooleanOutcomePair traverseOr(Node n, FlowScope scope) {
return traverseShortCircuitingBinOp(n, scope, false);
}
private BooleanOutcomePair traverseShortCircuitingBinOp(
Node n, FlowScope scope, boolean condition) {
Node left = n.getFirstChild();
Node right = n.getLastChild();
// type the left node
BooleanOutcomePair leftLiterals =
traverseWithinShortCircuitingBinOp(left,
scope.createChildFlowScope());
JSType leftType = left.getJSType();
// reverse abstract interpret the left node to produce the correct
// scope in which to verify the right node
FlowScope rightScope = reverseInterpreter.
getPreciserScopeKnowingConditionOutcome(
left, leftLiterals.getOutcomeFlowScope(left.getType(), condition),
condition);
// type the right node
BooleanOutcomePair rightLiterals =
traverseWithinShortCircuitingBinOp(
right, rightScope.createChildFlowScope());
JSType rightType = right.getJSType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> */
FlowScope getJoinedFlowScope() {
if (joinedScope == null) {
if (leftScope == rightScope) {
joinedScope = rightScope;
} else {
joinedScope = join(leftScope, rightScope);
}
}
return joinedScope;
}
/**
* Gets the outcome scope if we do know the outcome of the entire
* expression.
*/
FlowScope getOutcomeFlowScope(int nodeType, boolean outcome) {
if (nodeType == Token.AND && outcome ||
nodeType == Token.OR && !outcome) {
// We know that the whole expression must have executed.
return rightScope;
} else {
return getJoinedFlowScope();
}
}
}
private BooleanOutcomePair newBooleanOutcomePair(
JSType jsType, FlowScope flowScope) {
if (jsType == null) {
return new BooleanOutcomePair(
BooleanLiteralSet.BOTH, BooleanLiteralSet.BOTH, flowScope, flowScope);
}
return new BooleanOutcomePair(jsType.getPossibleToBooleanOutcomes(),
registry.getNativeType(BOOLEAN_TYPE).isSubtype(jsType) ?
BooleanLiteralSet.BOTH : BooleanLiteralSet.EMPTY,
flowScope, flowScope);
}
private void redeclareSimpleVar(
FlowScope scope, Node nameNode, JSType varType) {
Preconditions.checkState(nameNode.isName());
String varName = nameNode.getString();
if (varType == null) {
varType = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
if (isUnflowable(syntacticScope.getVar(varName))) {
return;
}
scope.inferSlotType(varName, varType);
}
private boolean isUnflowable(Var v) {
return v != null && v.isLocal() && v.isMarkedEscaped() &&
// It's OK to flow a variable in the scope where it's escaped.
v.getScope() == syntacticScope;
}
/**
* This method gets the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(nicks
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>antos): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
private JSType getNativeType(JSTypeNative typeId) {
return registry.getNativeType(typeId);
}
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> of a class. These are mostly validated
// during TypedScopeCreator, and we only look for the "dumb" cases here.
// object.prototype = ...;
if (property.equals("prototype")) {
if (objectJsType != null && objectJsType.isFunctionType()) {
FunctionType functionType = objectJsType.toMaybeFunctionType();
if (functionType.isConstructor()) {
JSType rvalueType = rvalue.getJSType();
validator.expectObject(t, rvalue, rvalueType,
OVERRIDING_PROTOTYPE_WITH_NON_OBJECT);
return;
}
}
}
// The generic checks for 'object.property' when 'object' is known,
// and 'property' is declared on it.
// object.property = ...;
ObjectType type = ObjectType.cast(
objectJsType.restrictByNotNullOrUndefined());
if (type != null) {
if (type.hasProperty(property) &&
!type.isPropertyTypeInferred(property) &&
!propertyIsImplicitCast(type, property)) {
JSType expectedType = type.getPropertyType(property);
if (!expectedType.isUnknownType()) {
validator.expectCanAssignToPropertyOf(
t, assign, getJSType(rvalue),
expectedType, object, property);
checkPropertyInheritanceOnGetpropAssign(
t, assign, object, property, info, expectedType);
return;
}
}
}
// If we couldn't get the property type with normal object property
// lookups, then check inheritance anyway with the unknown type.
checkPropertyInheritanceOnGetpropAssign(
t, assign, object, property, info, getNativeType(UNKNOWN_TYPE));
}
// Check qualified name sets to 'object' and 'object.property'.
// This can sometimes handle cases when the type of 'object' is not known.
// e.g.,
// var obj = createUnknownType();
// /** @type {number} */ obj.foo = true;
JSType leftType = getJSType(lvalue);
if (lvalue.isQualifiedName()) {
// variable with inferred type case
JSType rvalueType = getJSType(assign.getLastChild());
Var var = t.getScope().getVar(lvalue.getQualifiedName());
if
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> change the
* schema of the object type it is referring to.
*
* @param t the traversal
* @param key the assign node
*/
private void visitObjLitKey(NodeTraversal t, Node key, Node objlit) {
// Do not validate object lit value types in externs. We don't really care,
// and it makes it easier to generate externs.
if (objlit.isFromExterns()) {
ensureTyped(t, key);
return;
}
// TODO(johnlenz): Validate get and set function declarations are valid
// as is the functions can have "extraneous" bits.
// For getter and setter property definitions the
// r-value type != the property type.
Node rvalue = key.getFirstChild();
JSType rightType = NodeUtil.getObjectLitKeyTypeFromValueType(
key, getJSType(rvalue));
if (rightType == null) {
rightType = getNativeType(UNKNOWN_TYPE);
}
Node owner = objlit;
// Validate value is assignable to the key type.
JSType keyType = getJSType(key);
JSType allowedValueType = keyType;
if (allowedValueType.isEnumElementType()) {
allowedValueType =
allowedValueType.toMaybeEnumElementType().getPrimitiveType();
}
boolean valid = validator.expectCanAssignToPropertyOf(t, key,
rightType, allowedValueType,
owner, NodeUtil.getObjectLitKeyName(key));
if (valid) {
ensureTyped(t, key, rightType);
} else {
ensureTyped(t, key);
}
// Validate that the key type is assignable to the object property type.
// This is necessary as the objlit may have been cast to a non-literal
// object type.
// TODO(johnlenz): consider introducing a CAST node to the AST (or
// perhaps a parentheses node).
JSType objlitType = getJSType(objlit);
ObjectType type = ObjectType.cast(
objlitType.restrictByNotNullOrUndefined());
if (type != null) {
String property = NodeUtil.getObjectLitKeyName(key);
if (type.hasProperty(property) &&
!type.isPropertyTypeInferred(property) &&
!propertyIsImplicitCast(type, property)) {
validator
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>ize our compiler errors.
String abstractMethodMessage = (abstractMethodName != null)
? ", or " + abstractMethodName
: "";
compiler.report(
t.makeError(object, INVALID_INTERFACE_MEMBER_DECLARATION,
abstractMethodMessage));
}
if (assign.getLastChild().isFunction()
&& !NodeUtil.isEmptyBlock(assign.getLastChild().getLastChild())) {
compiler.report(
t.makeError(object, INTERFACE_FUNCTION_NOT_EMPTY,
abstractMethodName));
}
}
/**
* Visits a NAME node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
* @param parent The parent of the node n.
* @return whether the node is typeable or not
*/
boolean visitName(NodeTraversal t, Node n, Node parent) {
// At this stage, we need to determine whether this is a leaf
// node in an expression (which therefore needs to have a type
// assigned for it) versus some other decorative node that we
// can safely ignore. Function names, arguments (children of LP nodes) and
// variable declarations are ignored.
// TODO(user): remove this short-circuiting in favor of a
// pre order traversal of the FUNCTION, CATCH, LP and VAR nodes.
int parentNodeType = parent.getType();
if (parentNodeType == Token.FUNCTION ||
parentNodeType == Token.CATCH ||
parentNodeType == Token.PARAM_LIST ||
parentNodeType == Token.VAR) {
return false;
}
JSType type = n.getJSType();
if (type == null) {
type = getNativeType(UNKNOWN_TYPE);
Var var = t.getScope().getVar(n.getString());
if (var != null) {
JSType varType = var.getType();
if (varType != null) {
type = varType;
}
}
}
ensureTyped(t, n, type);
return true;
}
/**
* Visits a GETPROP node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> error reporting.
* @param n The node being visited.
* @param parent The parent of <code>n</code>
*/
private void visitGetProp(NodeTraversal t, Node n, Node parent) {
// GETPROP nodes have an assigned type on their node by the scope creator
// if this is an enum declaration. The only namespaced enum declarations
// that we allow are of the form object.name = ...;
if (n.getJSType() != null && parent.isAssign()) {
return;
}
// obj.prop or obj.method()
// Lots of types can appear on the left, a call to a void function can
// never be on the left. getPropertyType will decide what is acceptable
// and what isn't.
Node property = n.getLastChild();
Node objNode = n.getFirstChild();
JSType childType = getJSType(objNode);
// TODO(user): remove in favor of flagging every property access on
// non-object.
if (!validator.expectNotNullOrUndefined(t, n, childType,
"No properties on this expression", getNativeType(OBJECT_TYPE))) {
ensureTyped(t, n);
return;
}
checkPropertyAccess(childType, property.getString(), t, n);
ensureTyped(t, n);
}
/**
* Emit a warning if we can prove that a property cannot possibly be
* defined on an object. Note the difference between JS and a strictly
* statically typed language: we're checking if the property
* *cannot be defined*, whereas a java compiler would check if the
* property *can be undefined*.
*/
private void checkPropertyAccess(JSType childType, String propName,
NodeTraversal t, Node n) {
// If the property type is unknown, check the object type to see if it
// can ever be defined. We explicitly exclude CHECKED_UNKNOWN (for
// properties where we've checked that it exists, or for properties on
// objects that aren't in this binary).
JSType propType = getJSType(n);
if (propType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) {
childType = childType.autobox();
ObjectType objectType = ObjectType.cast(childType);
if (objectType != null
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>) {
// We special-case object types so that checks on enums can be
// much stricter, and so that we can use hasProperty (which is much
// faster in most cases).
if (!objectType.hasProperty(propName) ||
objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) {
if (objectType instanceof EnumType) {
report(t, n, INEXISTENT_ENUM_ELEMENT, propName);
} else {
checkPropertyAccessHelper(objectType, propName, t, n);
}
}
} else {
checkPropertyAccessHelper(childType, propName, t, n);
}
}
}
private void checkPropertyAccessHelper(JSType objectType, String propName,
NodeTraversal t, Node n) {
if (!objectType.isEmptyType() &&
reportMissingProperties && !isPropertyTest(n)) {
if (!typeRegistry.canPropertyBeDefined(objectType, propName)) {
report(t, n, INEXISTENT_PROPERTY, propName,
validator.getReadableJSTypeName(n.getFirstChild(), true));
}
}
}
/**
* Determines whether this node is testing for the existence of a property.
* If true, we will not emit warnings about a missing property.
*
* @param getProp The GETPROP being tested.
*/
private boolean isPropertyTest(Node getProp) {
Node parent = getProp.getParent();
switch (parent.getType()) {
case Token.CALL:
return parent.getFirstChild() != getProp &&
compiler.getCodingConvention().isPropertyTestFunction(parent);
case Token.IF:
case Token.WHILE:
case Token.DO:
case Token.FOR:
return NodeUtil.getConditionExpression(parent) == getProp;
case Token.INSTANCEOF:
case Token.TYPEOF:
return true;
case Token.AND:
case Token.HOOK:
return parent.getFirstChild() == getProp;
case Token.NOT:
return parent.getParent().isOr() &&
parent.getParent().getFirstChild() == parent;
}
return false;
}
/**
* Visits a GETELEM node.
*
* @param t The node traversal object that supplies context, such as
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitGetElem(NodeTraversal t, Node n) {
Node left = n.getFirstChild();
Node right = n.getLastChild();
validator.expectIndexMatch(t, n, getJSType(left), getJSType(right));
ensureTyped(t, n);
}
/**
* Visits a VAR node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitVar(NodeTraversal t, Node n) {
// TODO(nicksantos): Fix this so that the doc info always shows up
// on the NAME node. We probably want to wait for the parser
// merge to fix this.
JSDocInfo varInfo = n.hasOneChild() ? n.getJSDocInfo() : null;
for (Node name : n.children()) {
Node value = name.getFirstChild();
// A null var would indicate a bug in the scope creation logic.
Var var = t.getScope().getVar(name.getString());
if (value != null) {
JSType valueType = getJSType(value);
JSType nameType = var.getType();
nameType = (nameType == null) ? getNativeType(UNKNOWN_TYPE) : nameType;
JSDocInfo info = name.getJSDocInfo();
if (info == null) {
info = varInfo;
}
checkEnumAlias(t, info, value);
if (var.isTypeInferred()) {
ensureTyped(t, name, valueType);
} else {
validator.expectCanAssignTo(
t, value, valueType, nameType, "initializing variable");
}
}
}
}
/**
* Visits a NEW node.
*/
private void visitNew(NodeTraversal t, Node n) {
Node constructor = n.getFirstChild();
JSType type = getJSType(constructor).restrictByNotNullOrUndefined();
if (type.isConstructor() || type.isEmptyType() || type.isUnknownType()) {
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>();
if (jsType == null) {
// TODO(nicksantos): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
// TODO(nicksantos): TypeCheck should never be attaching types to nodes.
// All types should be attached by TypeInference. This is not true today
// for legacy reasons. There are a number of places where TypeInference
// doesn't attach a type, as a signal to TypeCheck that it needs to check
// that node's type.
/**
* Ensure that the given node has a type. If it does not have one,
* attach the UNKNOWN_TYPE.
*/
private void ensureTyped(NodeTraversal t, Node n) {
ensureTyped(t, n, getNativeType(UNKNOWN_TYPE));
}
private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) {
ensureTyped(t, n, getNativeType(type));
}
/**
* Enforces type casts, and ensures the node is typed.
*
* A cast in the way that we use it in JSDoc annotations never
* alters the generated code and therefore never can induce any runtime
* operation. What this means is that a 'cast' is really just a compile
* time constraint on the underlying value. In the future, we may add
* support for run-time casts for compiled tests.
*
* To ensure some shred of sanity, we enforce the notion that the
* type you are casting to may only meaningfully be a narrower type
* than the underlying declared type. We also invalidate optimizations
* on bad type casts.
*
* @param t The traversal object needed to report errors.
* @param n The node getting a type assigned to it.
* @param type The type to be assigned.
*/
private void ensureTyped(NodeTraversal t, Node n, JSType type) {
// Make sure FUNCTION nodes always get function type.
Preconditions.checkState(!n.isFunction() ||
type.isFunctionType()
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> properties of this type are also NoResolved types,
* and comparisons to other types always have an unknown result.
*
* @author nicksantos@google.com (Nick Santos)
*/
class NoResolvedType extends NoType {
private static final long serialVersionUID = 1L;
NoResolvedType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNoResolvedType() {
return true;
}
@Override
public boolean isNoType() {
return false;
}
@Override
public JSType getPropertyType(String propertyName) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtypeHelper(this, that)) {
return true;
} else {
return !that.isNoType();
}
}
@Override
String toStringHelper(boolean forAnnotations) {
return forAnnotations ? "?" : "NoResolvedType";
}
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>> slot = getSlot(property);
if (slot == null) {
return false;
}
return !slot.isTypeInferred();
}
@Override
void collectPropertyNames(Set<String> props) {
for (String prop : properties.keySet()) {
props.add(prop);
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
implicitPrototype.collectPropertyNames(props);
}
}
@Override
public boolean isPropertyTypeInferred(String property) {
StaticSlot<JSType> slot = getSlot(property);
if (slot == null) {
return false;
}
return slot.isTypeInferred();
}
@Override
public JSType getPropertyType(String property) {
StaticSlot<JSType> slot = getSlot(property);
if (slot == null) {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return slot.getType();
}
@Override
public boolean isPropertyInExterns(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.isFromExterns();
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyInExterns(propertyName);
}
return false;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
Node propertyNode) {
if (hasOwnDeclaredProperty(name)) {
return false;
}
Property newProp = new Property(
name, type, inferred, propertyNode);
Property oldProp = properties.get(name);
if (oldProp != null) {
// This is to keep previously inferred JsDoc info, e.g., in a
// replaceScript scenario.
newProp.setJSDocInfo(oldProp.getJSDocInfo());
}
properties.put(name, newProp);
return true;
}
@Override
public boolean removeProperty(String name) {
return properties.remove(name) != null;
}
@Override
public Node getPropertyNode(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.getNode();
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>SubSubBar.getInstanceType();
final ObjectType googObject = registry.createAnonymousObjectType();
googObject.defineDeclaredProperty("Bar", googBar, null);
namedGoogBar.resolve(null, new AbstractStaticScope<JSType>() {
@Override
public StaticSlot<JSType> getSlot(String name) {
if ("goog".equals(name)) {
return new SimpleSlot("goog", googObject, false);
} else {
return null;
}
}
});
assertNotNull(namedGoogBar.getImplicitPrototype());
forwardDeclaredNamedType =
new NamedType(registry, "forwardDeclared", "source", 1, 0);
registry.forwardDeclareType("forwardDeclared");
forwardDeclaredNamedType.resolve(
new SimpleErrorReporter(), EMPTY_SCOPE);
types = ImmutableList.of(
NO_OBJECT_TYPE,
NO_RESOLVED_TYPE,
NO_TYPE,
BOOLEAN_OBJECT_TYPE,
BOOLEAN_TYPE,
STRING_OBJECT_TYPE,
STRING_TYPE,
VOID_TYPE,
UNKNOWN_TYPE,
NULL_TYPE,
NUMBER_OBJECT_TYPE,
NUMBER_TYPE,
DATE_TYPE,
ERROR_TYPE,
SYNTAX_ERROR_TYPE,
dateMethod,
functionType,
unresolvedNamedType,
googBar,
googSubBar,
googSubSubBar,
namedGoogBar,
googBar.getInstanceType(),
subclassOfUnresolvedNamedType,
subclassCtor,
recordType,
enumType,
elementsType,
googBar,
googSubBar,
forwardDeclaredNamedType);
}
/**
* Tests the behavior of the top constructor type.
*/
public void testUniversalConstructorType() throws Exception {
// isXxx
assertFalse(U2U_CONSTRUCTOR_TYPE.isNoObjectType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isNoType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isArrayType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isBooleanValueType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isDateType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isEnumElementType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isNullType());
assertFalse(U2U_CONSTRUCTOR_TYPE.isNamedType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>U2U_CONSTRUCTOR_TYPE.matchesObjectContext());
assertFalse(U2U_CONSTRUCTOR_TYPE.matchesStringContext());
assertFalse(U2U_CONSTRUCTOR_TYPE.matchesUint32Context());
// toString
assertEquals("Function",
U2U_CONSTRUCTOR_TYPE.toString());
assertTrue(U2U_CONSTRUCTOR_TYPE.hasDisplayName());
assertEquals("Function", U2U_CONSTRUCTOR_TYPE.getDisplayName());
// getPropertyType
assertTypeEquals(UNKNOWN_TYPE,
U2U_CONSTRUCTOR_TYPE.getPropertyType("anyProperty"));
assertTrue(U2U_CONSTRUCTOR_TYPE.isNativeObjectType());
Asserts.assertResolvesToSame(U2U_CONSTRUCTOR_TYPE);
assertTrue(U2U_CONSTRUCTOR_TYPE.isNominalConstructor());
}
/**
* Tests the behavior of the Bottom Object type.
*/
public void testNoObjectType() throws Exception {
// isXxx
assertTrue(NO_OBJECT_TYPE.isNoObjectType());
assertFalse(NO_OBJECT_TYPE.isNoType());
assertFalse(NO_OBJECT_TYPE.isArrayType());
assertFalse(NO_OBJECT_TYPE.isBooleanValueType());
assertFalse(NO_OBJECT_TYPE.isDateType());
assertFalse(NO_OBJECT_TYPE.isEnumElementType());
assertFalse(NO_OBJECT_TYPE.isNullType());
assertFalse(NO_OBJECT_TYPE.isNamedType());
assertFalse(NO_OBJECT_TYPE.isNullType());
assertTrue(NO_OBJECT_TYPE.isNumber());
assertFalse(NO_OBJECT_TYPE.isNumberObjectType());
assertFalse(NO_OBJECT_TYPE.isNumberValueType());
assertTrue(NO_OBJECT_TYPE.isObject());
assertFalse(NO_OBJECT_TYPE.isFunctionPrototypeType());
assertFalse(NO_OBJECT_TYPE.isRegexpType());
assertTrue(NO_OBJECT_TYPE.isString());
assertFalse(NO_OBJECT_TYPE.isStringObjectType());
assertFalse(NO_OBJECT_TYPE.isStringValueType());
assertFalse(NO_OBJECT_TYPE.isEnumType());
assertFalse(NO_OBJECT_TYPE.isUnionType());
assertFalse(NO_OBJECT_TYPE.isAllType());
assertFalse(NO_OBJECT_TYPE.isVoidType());
assertTrue(NO_OBJECT_TYPE.isConstructor());
assertFalse(NO_OBJECT_TYPE.isInstanceType());
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(SYNTAX_ERROR_TYPE));
assertTrue(NO_RESOLVED_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(NO_RESOLVED_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertTrue(NO_RESOLVED_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
// isNullable
assertTrue(NO_RESOLVED_TYPE.isNullable());
// isObject
assertTrue(NO_RESOLVED_TYPE.isObject());
// matchesXxx
assertTrue(NO_RESOLVED_TYPE.matchesInt32Context());
assertTrue(NO_RESOLVED_TYPE.matchesNumberContext());
assertTrue(NO_RESOLVED_TYPE.matchesObjectContext());
assertTrue(NO_RESOLVED_TYPE.matchesStringContext());
assertTrue(NO_RESOLVED_TYPE.matchesUint32Context());
// toString
assertEquals("NoResolvedType", NO_RESOLVED_TYPE.toString());
assertEquals(null, NO_RESOLVED_TYPE.getDisplayName());
assertFalse(NO_RESOLVED_TYPE.hasDisplayName());
// getPropertyType
assertTypeEquals(CHECKED_UNKNOWN_TYPE,
NO_RESOLVED_TYPE.getPropertyType("anyProperty"));
Asserts.assertResolvesToSame(NO_RESOLVED_TYPE);
assertTrue(forwardDeclaredNamedType.isEmptyType());
assertTrue(forwardDeclaredNamedType.isNoResolvedType());
}
/**
* Tests the behavior of the Array type.
*/
public void testArrayType() throws Exception {
// isXxx
assertTrue(ARRAY_TYPE.isArrayType());
assertFalse(ARRAY_TYPE.isBooleanValueType());
assertFalse(ARRAY_TYPE.isDateType());
assertFalse(ARRAY_TYPE.isEnumElementType());
assertFalse(ARRAY_TYPE.isNamedType());
assertFalse(ARRAY_TYPE.isNullType());
assertFalse(ARRAY_TYPE.isNumber());
assertFalse(ARRAY_TYPE.isNumberObjectType());
assertFalse(ARRAY_TYPE.isNumberValueType());
assertTrue(ARRAY_TYPE.isObject());
assertFalse(ARRAY_TYPE.isFunctionPrototypeType());
assertTrue(ARRAY_TYPE.getImplicitPrototype().isFunctionPrototypeType());
assertFalse(ARRAY_TYPE.isRegexpType());
assertFalse(ARRAY_TYPE.isString());
assertFalse(ARRAY_TYPE.isStringObjectType());
assertFalse(ARRAY_TYPE.isStringValueType());
assertFalse(ARRAY_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>LeastSupertype(ALL_TYPE));
assertTypeEquals(createUnionType(STRING_OBJECT_TYPE, ARRAY_TYPE),
ARRAY_TYPE.getLeastSupertype(STRING_OBJECT_TYPE));
assertTypeEquals(createUnionType(NUMBER_TYPE, ARRAY_TYPE),
ARRAY_TYPE.getLeastSupertype(NUMBER_TYPE));
assertTypeEquals(createUnionType(ARRAY_TYPE, functionType),
ARRAY_TYPE.getLeastSupertype(functionType));
assertTypeEquals(OBJECT_TYPE, ARRAY_TYPE.getLeastSupertype(OBJECT_TYPE));
assertTypeEquals(createUnionType(DATE_TYPE, ARRAY_TYPE),
ARRAY_TYPE.getLeastSupertype(DATE_TYPE));
assertTypeEquals(createUnionType(REGEXP_TYPE, ARRAY_TYPE),
ARRAY_TYPE.getLeastSupertype(REGEXP_TYPE));
// getPropertyType
assertEquals(17, ARRAY_TYPE.getImplicitPrototype().getPropertiesCount());
assertEquals(18, ARRAY_TYPE.getPropertiesCount());
assertReturnTypeEquals(ARRAY_TYPE,
ARRAY_TYPE.getPropertyType("constructor"));
assertReturnTypeEquals(STRING_TYPE,
ARRAY_TYPE.getPropertyType("toString"));
assertReturnTypeEquals(STRING_TYPE,
ARRAY_TYPE.getPropertyType("toLocaleString"));
assertReturnTypeEquals(ARRAY_TYPE, ARRAY_TYPE.getPropertyType("concat"));
assertReturnTypeEquals(STRING_TYPE,
ARRAY_TYPE.getPropertyType("join"));
assertReturnTypeEquals(UNKNOWN_TYPE, ARRAY_TYPE.getPropertyType("pop"));
assertReturnTypeEquals(NUMBER_TYPE, ARRAY_TYPE.getPropertyType("push"));
assertReturnTypeEquals(ARRAY_TYPE, ARRAY_TYPE.getPropertyType("reverse"));
assertReturnTypeEquals(UNKNOWN_TYPE, ARRAY_TYPE.getPropertyType("shift"));
assertReturnTypeEquals(ARRAY_TYPE, ARRAY_TYPE.getPropertyType("slice"));
assertReturnTypeEquals(ARRAY_TYPE, ARRAY_TYPE.getPropertyType("sort"));
assertReturnTypeEquals(ARRAY_TYPE, ARRAY_TYPE.getPropertyType("splice"));
assertReturnTypeEquals(NUMBER_TYPE, ARRAY_TYPE.getPropertyType("unshift"));
assertTypeEquals(NUMBER_TYPE, ARRAY_TYPE.getPropertyType("length"));
// isPropertyType*
assertPropertyTypeDeclared(ARRAY_TYPE, "pop");
// matchesXxx
assertFalse(ARRAY_TYPE.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>matchesInt32Context());
assertFalse(ARRAY_TYPE.matchesNumberContext());
assertTrue(ARRAY_TYPE.matchesObjectContext());
assertTrue(ARRAY_TYPE.matchesStringContext());
assertFalse(ARRAY_TYPE.matchesUint32Context());
// toString
assertEquals("Array", ARRAY_TYPE.toString());
assertTrue(ARRAY_TYPE.hasDisplayName());
assertEquals("Array", ARRAY_TYPE.getDisplayName());
assertTrue(ARRAY_TYPE.isNativeObjectType());
Asserts.assertResolvesToSame(ARRAY_TYPE);
assertFalse(ARRAY_TYPE.isNominalConstructor());
assertTrue(ARRAY_TYPE.getConstructor().isNominalConstructor());
}
/**
* Tests the behavior of the unknown type.
*/
public void testUnknownType() throws Exception {
// isXxx
assertFalse(UNKNOWN_TYPE.isArrayType());
assertFalse(UNKNOWN_TYPE.isBooleanObjectType());
assertFalse(UNKNOWN_TYPE.isBooleanValueType());
assertFalse(UNKNOWN_TYPE.isDateType());
assertFalse(UNKNOWN_TYPE.isEnumElementType());
assertFalse(UNKNOWN_TYPE.isNamedType());
assertFalse(UNKNOWN_TYPE.isNullType());
assertFalse(UNKNOWN_TYPE.isNumberObjectType());
assertFalse(UNKNOWN_TYPE.isNumberValueType());
assertTrue(UNKNOWN_TYPE.isObject());
assertFalse(UNKNOWN_TYPE.isFunctionPrototypeType());
assertFalse(UNKNOWN_TYPE.isRegexpType());
assertFalse(UNKNOWN_TYPE.isStringObjectType());
assertFalse(UNKNOWN_TYPE.isStringValueType());
assertFalse(UNKNOWN_TYPE.isEnumType());
assertFalse(UNKNOWN_TYPE.isUnionType());
assertTrue(UNKNOWN_TYPE.isUnknownType());
assertFalse(UNKNOWN_TYPE.isVoidType());
assertFalse(UNKNOWN_TYPE.isConstructor());
assertFalse(UNKNOWN_TYPE.isInstanceType());
// autoboxesTo
assertNull(UNKNOWN_TYPE.autoboxesTo());
// canAssignTo
assertTrue(UNKNOWN_TYPE.canAssignTo(UNKNOWN_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(STRING_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(NUMBER_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(functionType));
assertTrue(UNKNOWN_TYPE.canAssignTo(recordType));
assertTrue(UNKNOWN_TYPE.canAssignTo(NULL_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(OBJECT_TYPE));
assertTrue(UNKNOWN_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>TYPE.canAssignTo(DATE_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(namedGoogBar));
assertTrue(UNKNOWN_TYPE.canAssignTo(unresolvedNamedType));
assertTrue(UNKNOWN_TYPE.canAssignTo(REGEXP_TYPE));
assertTrue(UNKNOWN_TYPE.canAssignTo(VOID_TYPE));
// canBeCalled
assertTrue(UNKNOWN_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(UNKNOWN_TYPE, UNKNOWN_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, STRING_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, functionType);
assertCanTestForEqualityWith(UNKNOWN_TYPE, recordType);
assertCanTestForEqualityWith(UNKNOWN_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(UNKNOWN_TYPE, BOOLEAN_TYPE);
// canTestForShallowEqualityWith
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(functionType));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(recordType));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertTrue(UNKNOWN_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
// canHaveNullValue
assertTrue(UNKNOWN_TYPE.isNullable());
// getGreatestCommonType
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(UNKNOWN_TYPE));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(STRING_TYPE));
assertTypeEquals(UNKNOWN_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>TYPE,
UNKNOWN_TYPE.getLeastSupertype(NUMBER_TYPE));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(functionType));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(OBJECT_TYPE));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(DATE_TYPE));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getLeastSupertype(REGEXP_TYPE));
// matchesXxx
assertTrue(UNKNOWN_TYPE.matchesInt32Context());
assertTrue(UNKNOWN_TYPE.matchesNumberContext());
assertTrue(UNKNOWN_TYPE.matchesObjectContext());
assertTrue(UNKNOWN_TYPE.matchesStringContext());
assertTrue(UNKNOWN_TYPE.matchesUint32Context());
// isPropertyType*
assertPropertyTypeUnknown(UNKNOWN_TYPE, "XXX");
// toString
assertEquals("?", UNKNOWN_TYPE.toString());
assertTrue(UNKNOWN_TYPE.hasDisplayName());
assertEquals("Unknown", UNKNOWN_TYPE.getDisplayName());
Asserts.assertResolvesToSame(UNKNOWN_TYPE);
assertFalse(UNKNOWN_TYPE.isNominalConstructor());
}
/**
* Tests the behavior of the unknown type.
*/
public void testAllType() throws Exception {
// isXxx
assertFalse(ALL_TYPE.isArrayType());
assertFalse(ALL_TYPE.isBooleanValueType());
assertFalse(ALL_TYPE.isDateType());
assertFalse(ALL_TYPE.isEnumElementType());
assertFalse(ALL_TYPE.isNamedType());
assertFalse(ALL_TYPE.isNullType());
assertFalse(ALL_TYPE.isNumber());
assertFalse(ALL_TYPE.isNumberObjectType());
assertFalse(ALL_TYPE.isNumberValueType());
assertFalse(ALL_TYPE.isObject());
assertFalse(ALL_TYPE.isFunctionPrototypeType());
assertFalse(ALL_TYPE.isRegexpType());
assertFalse(ALL_TYPE.isString());
assertFalse(ALL_TYPE.isStringObjectType());
assertFalse(ALL_TYPE.isStringValueType());
assertFalse(ALL_TYPE.isEnumType());
assertFalse(ALL_TYPE.isUnionType());
assertTrue(ALL_TYPE.isAllType());
assertFalse(ALL_TYPE.isVoidType());
assertFalse(ALL_TYPE.isConstructor());
assertFalse(ALL_TYPE.isInstanceType());
// canAssignTo
assertFalse(ALL_TYPE
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>.canAssignTo(NO_TYPE));
assertFalse(ALL_TYPE.canAssignTo(NO_OBJECT_TYPE));
assertTrue(ALL_TYPE.canAssignTo(ALL_TYPE));
assertFalse(ALL_TYPE.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(ALL_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(ALL_TYPE.canAssignTo(functionType));
assertFalse(ALL_TYPE.canAssignTo(recordType));
assertFalse(ALL_TYPE.canAssignTo(NULL_TYPE));
assertFalse(ALL_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(ALL_TYPE.canAssignTo(DATE_TYPE));
assertTrue(ALL_TYPE.canAssignTo(unresolvedNamedType));
assertFalse(ALL_TYPE.canAssignTo(namedGoogBar));
assertFalse(ALL_TYPE.canAssignTo(REGEXP_TYPE));
assertFalse(ALL_TYPE.canAssignTo(VOID_TYPE));
assertTrue(ALL_TYPE.canAssignTo(UNKNOWN_TYPE));
// canBeCalled
assertFalse(ALL_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(ALL_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, functionType);
assertCanTestForEqualityWith(ALL_TYPE, recordType);
assertCanTestForEqualityWith(ALL_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(ALL_TYPE, REGEXP_TYPE);
// canTestForShallowEqualityWith
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertTrue(ALL_TYPE.canTest
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>ForShallowEqualityWith(DATE_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(functionType));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(recordType));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(NULL_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertTrue(ALL_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
// isNullable
assertFalse(ALL_TYPE.isNullable());
// getLeastSupertype
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getLeastSupertype(ALL_TYPE));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getLeastSupertype(UNKNOWN_TYPE));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getLeastSupertype(STRING_OBJECT_TYPE));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getLeastSupertype(NUMBER_TYPE));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getLeastSupertype(functionType));
assertTypeEquals(
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>());
assertTrue(OBJECT_TYPE.isInstanceType());
// canAssignTo
assertFalse(OBJECT_TYPE.canAssignTo(NO_TYPE));
assertTrue(OBJECT_TYPE.canAssignTo(ALL_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(functionType));
assertFalse(OBJECT_TYPE.canAssignTo(recordType));
assertFalse(OBJECT_TYPE.canAssignTo(NULL_TYPE));
assertTrue(OBJECT_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(DATE_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(namedGoogBar));
assertTrue(OBJECT_TYPE.canAssignTo(unresolvedNamedType));
assertFalse(OBJECT_TYPE.canAssignTo(REGEXP_TYPE));
assertFalse(OBJECT_TYPE.canAssignTo(ARRAY_TYPE));
assertTrue(OBJECT_TYPE.canAssignTo(UNKNOWN_TYPE));
// canBeCalled
assertFalse(OBJECT_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(OBJECT_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, STRING_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, BOOLEAN_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, functionType);
assertCanTestForEqualityWith(OBJECT_TYPE, recordType);
assertCannotTestForEqualityWith(OBJECT_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, ARRAY_TYPE);
assertCanTestForEqualityWith(OBJECT_TYPE, UNKNOWN_TYPE);
// canTestForShallowEqualityWith
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(NO_OBJECT_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(OBJECT_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(functionType));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(recordType));
assertFalse(OBJECT_TYPE.canTestForShallowEqualityWith(NULL_TYPE));
assertFalse(OBJECT_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertTrue(OBJECT_TYPE.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertFalse(OBJECT_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(OBJECT_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(OBJECT_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// isNullable
assertFalse(OBJECT_TYPE.isNullable());
// getLeastSupertype
assertTypeEquals(ALL_TYPE,
OBJECT_TYPE.getLeastSupertype(ALL_TYPE));
assertTypeEquals(OBJECT_TYPE
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>,
OBJECT_TYPE.getLeastSupertype(STRING_OBJECT_TYPE));
assertTypeEquals(createUnionType(OBJECT_TYPE, NUMBER_TYPE),
OBJECT_TYPE.getLeastSupertype(NUMBER_TYPE));
assertTypeEquals(OBJECT_TYPE,
OBJECT_TYPE.getLeastSupertype(functionType));
assertTypeEquals(OBJECT_TYPE,
OBJECT_TYPE.getLeastSupertype(OBJECT_TYPE));
assertTypeEquals(OBJECT_TYPE,
OBJECT_TYPE.getLeastSupertype(DATE_TYPE));
assertTypeEquals(OBJECT_TYPE,
OBJECT_TYPE.getLeastSupertype(REGEXP_TYPE));
// getPropertyType
assertEquals(7, OBJECT_TYPE.getPropertiesCount());
assertReturnTypeEquals(OBJECT_TYPE,
OBJECT_TYPE.getPropertyType("constructor"));
assertReturnTypeEquals(STRING_TYPE,
OBJECT_TYPE.getPropertyType("toString"));
assertReturnTypeEquals(STRING_TYPE,
OBJECT_TYPE.getPropertyType("toLocaleString"));
assertReturnTypeEquals(UNKNOWN_TYPE,
OBJECT_TYPE.getPropertyType("valueOf"));
assertReturnTypeEquals(BOOLEAN_TYPE,
OBJECT_TYPE.getPropertyType("hasOwnProperty"));
assertReturnTypeEquals(BOOLEAN_TYPE,
OBJECT_TYPE.getPropertyType("isPrototypeOf"));
assertReturnTypeEquals(BOOLEAN_TYPE,
OBJECT_TYPE.getPropertyType("propertyIsEnumerable"));
// matchesXxx
assertFalse(OBJECT_TYPE.matchesInt32Context());
assertFalse(OBJECT_TYPE.matchesNumberContext());
assertTrue(OBJECT_TYPE.matchesObjectContext());
assertTrue(OBJECT_TYPE.matchesStringContext());
assertFalse(OBJECT_TYPE.matchesUint32Context());
// implicit prototype
assertTypeEquals(OBJECT_PROTOTYPE, OBJECT_TYPE.getImplicitPrototype());
// toString
assertEquals("Object", OBJECT_TYPE.toString());
assertTrue(OBJECT_TYPE.isNativeObjectType());
assertTrue(OBJECT_TYPE.getImplicitPrototype().isNativeObjectType());
Asserts.assertResolvesToSame(OBJECT_TYPE);
assertFalse(OBJECT_TYPE.isNominalConstructor());
assertTrue(OBJECT_TYPE.getConstructor().isNominalConstructor());
}
/**
* Tests the behavior of the number value type.
*/
public void testNumberObjectType() throws Exception {
// isXxx
assertFalse(NUMBER_OBJECT_TYPE.isArrayType());
assertFalse(NUMBER_OBJECT
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>)));
assertFalse(NUMBER_OBJECT_TYPE.canAssignTo(
createUnionType(NUMBER_TYPE, NULL_TYPE)));
assertTrue(NUMBER_OBJECT_TYPE.canAssignTo(UNKNOWN_TYPE));
// canBeCalled
assertFalse(NUMBER_OBJECT_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, NO_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, NO_OBJECT_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, functionType);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, elementsType);
assertCannotTestForEqualityWith(NUMBER_OBJECT_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(NUMBER_OBJECT_TYPE, ARRAY_TYPE);
// canTestForShallowEqualityWith
assertTrue(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertTrue(NUMBER_OBJECT_TYPE.
canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.
canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.
canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEqualityWith(functionType));
assertFalse(NUMBER_OBJECT_TYPE.canTestForShallowEquality
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>canAssignTo(NUMBER_TYPE));
assertFalse(NUMBER_TYPE.canAssignTo(functionType));
assertFalse(NUMBER_TYPE.canAssignTo(NULL_TYPE));
assertFalse(NUMBER_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canAssignTo(DATE_TYPE));
assertTrue(NUMBER_TYPE.canAssignTo(unresolvedNamedType));
assertFalse(NUMBER_TYPE.canAssignTo(namedGoogBar));
assertTrue(NUMBER_TYPE.canAssignTo(
createUnionType(NUMBER_TYPE, NULL_TYPE)));
assertTrue(NUMBER_TYPE.canAssignTo(UNKNOWN_TYPE));
// canBeCalled
assertFalse(NUMBER_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(NUMBER_TYPE, NO_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, NO_OBJECT_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, STRING_OBJECT_TYPE);
assertCannotTestForEqualityWith(NUMBER_TYPE, functionType);
assertCannotTestForEqualityWith(NUMBER_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, ARRAY_TYPE);
assertCanTestForEqualityWith(NUMBER_TYPE, UNKNOWN_TYPE);
// canTestForShallowEqualityWith
assertTrue(NUMBER_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(NUMBER_TYPE
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(functionType));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(NULL_TYPE));
assertTrue(NUMBER_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertFalse(NUMBER_TYPE.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(NUMBER_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(NUMBER_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(NUMBER_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// isNullable
assertFalse(NUMBER_TYPE.isNullable());
// getLeastSupertype
assertTypeEquals(ALL_TYPE,
NUMBER_TYPE.getLeastSupertype(ALL_TYPE));
assertTypeEquals(createUnionType(NUMBER_TYPE, STRING_OBJECT_TYPE),
NUMBER_TYPE.getLeastSupertype(STRING_OBJECT_TYPE));
assertTypeEquals(NUMBER_TYPE,
NUMBER_TYPE.getLeastSupertype(NUMBER_TYPE));
assertTypeEquals(createUnionType(NUMBER_TYPE, functionType),
NUMBER_TYPE.getLeastSupertype(functionType));
assertTypeEquals(createUnionType(NUMBER_TYPE, OBJECT_TYPE),
NUMBER_TYPE.getLeastSupertype(OBJECT_TYPE));
assertTypeEquals(createUnionType(NUMBER_TYPE,
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(STRING_OBJECT_TYPE));
assertFalse(NULL_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(NULL_TYPE.canAssignTo(functionType));
assertFalse(NULL_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(NULL_TYPE.canAssignTo(DATE_TYPE));
assertFalse(NULL_TYPE.canAssignTo(REGEXP_TYPE));
assertFalse(NULL_TYPE.canAssignTo(ARRAY_TYPE));
assertTrue(NULL_TYPE.canAssignTo(UNKNOWN_TYPE));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(NO_OBJECT_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(NO_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(NULL_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(ALL_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(STRING_OBJECT_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(NUMBER_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(functionType)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(OBJECT_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(DATE_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(REGEXP_TYPE)));
assertTrue(NULL_TYPE.canAssignTo(createNullableType(ARRAY_TYPE)));
// canBeCalled
assertFalse(NULL_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(NULL_TYPE, NO_TYPE);
assertCanTestForEqualityWith(NULL_TYPE, NO_OBJECT_TYPE);
assertCanTestForEqualityWith(NULL_TYPE, ALL_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, ARRAY_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, BOOLEAN_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, BOOLEAN_OBJECT_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, DATE_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, ERROR_TYPE);
assertCannotTestForEqualityWith(NULL_TYPE, EVAL_ERROR_TYPE);
assertCannotTestForEqualityWith(NULL_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>TYPE.canAssignTo(REGEXP_TYPE));
assertFalse(STRING_OBJECT_TYPE.canAssignTo(ARRAY_TYPE));
assertFalse(STRING_OBJECT_TYPE.canAssignTo(STRING_TYPE));
// canBeCalled
assertFalse(STRING_OBJECT_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, STRING_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, functionType);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, BOOLEAN_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, BOOLEAN_OBJECT_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, ARRAY_TYPE);
assertCanTestForEqualityWith(STRING_OBJECT_TYPE, UNKNOWN_TYPE);
// canTestForShallowEqualityWith
assertTrue(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertTrue(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(functionType));
assertFalse(STRING_OBJECT_TYPE.canTestForSh
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>allowEqualityWith(NULL_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertTrue(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertTrue(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(STRING_OBJECT_TYPE.
canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(STRING_OBJECT_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// properties (ECMA-262 page 98 - 106)
assertEquals(23, STRING_OBJECT_TYPE.getImplicitPrototype().
getPropertiesCount());
assertEquals(24, STRING_OBJECT_TYPE.getPropertiesCount());
assertReturnTypeEquals(STRING_TYPE,
STRING_OBJECT_TYPE.getPropertyType("toString"));
assertReturnTypeEquals(STRING_TYPE,
STRING_OBJECT_TYPE.getPropertyType("valueOf"));
assertReturnTypeEquals(STRING_TYPE,
STRING_OBJECT_TYPE.getPropertyType("charAt"));
assertReturnTypeEquals(NUMBER_TYPE,
STRING_OBJECT_TYPE.getPropertyType("charCodeAt"));
assertReturnTypeEquals(STRING_TYPE,
STRING_OBJECT_TYPE.getPropertyType("concat"));
assertReturnTypeEquals(NUMBER_TYPE,
STRING_OBJECT_TYPE.getPropertyType("indexOf"));
assert
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
assertFalse(STRING_TYPE.isBooleanObjectType());
assertFalse(STRING_TYPE.isBooleanValueType());
assertFalse(STRING_TYPE.isDateType());
assertFalse(STRING_TYPE.isEnumElementType());
assertFalse(STRING_TYPE.isNamedType());
assertFalse(STRING_TYPE.isNullType());
assertFalse(STRING_TYPE.isNumber());
assertFalse(STRING_TYPE.isNumberObjectType());
assertFalse(STRING_TYPE.isNumberValueType());
assertFalse(STRING_TYPE.isFunctionPrototypeType());
assertFalse(STRING_TYPE.isRegexpType());
assertTrue(STRING_TYPE.isString());
assertFalse(STRING_TYPE.isStringObjectType());
assertTrue(STRING_TYPE.isStringValueType());
assertFalse(STRING_TYPE.isEnumType());
assertFalse(STRING_TYPE.isUnionType());
assertFalse(STRING_TYPE.isAllType());
assertFalse(STRING_TYPE.isVoidType());
assertFalse(STRING_TYPE.isConstructor());
assertFalse(STRING_TYPE.isInstanceType());
// autoboxesTo
assertTypeEquals(STRING_OBJECT_TYPE, STRING_TYPE.autoboxesTo());
// unboxesTo
assertTypeEquals(STRING_TYPE, STRING_OBJECT_TYPE.unboxesTo());
// canAssignTo
assertTrue(STRING_TYPE.canAssignTo(ALL_TYPE));
assertFalse(STRING_TYPE.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(STRING_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(STRING_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(STRING_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(STRING_TYPE.canAssignTo(DATE_TYPE));
assertFalse(STRING_TYPE.canAssignTo(REGEXP_TYPE));
assertFalse(STRING_TYPE.canAssignTo(ARRAY_TYPE));
assertTrue(STRING_TYPE.canAssignTo(STRING_TYPE));
assertTrue(STRING_TYPE.canAssignTo(UNKNOWN_TYPE));
// canBeCalled
assertFalse(STRING_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(STRING_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, STRING_OBJECT_TYPE);
assertCannotTestForEqualityWith(STRING_TYPE, functionType);
assertCanTestForEqualityWith(STRING_TYPE, OBJECT_TYPE);
assertCanTestFor
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>EqualityWith(STRING_TYPE, NUMBER_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, BOOLEAN_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, BOOLEAN_OBJECT_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, ARRAY_TYPE);
assertCanTestForEqualityWith(STRING_TYPE, UNKNOWN_TYPE);
// canTestForShallowEqualityWith
assertTrue(STRING_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(functionType));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(NULL_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertFalse(STRING_TYPE.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertTrue(STRING_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertFalse(STRING_TYPE.canTestForShallow
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>EqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(STRING_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(STRING_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(STRING_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// matchesXxx
assertTrue(STRING_TYPE.matchesInt32Context());
assertTrue(STRING_TYPE.matchesNumberContext());
assertTrue(STRING_TYPE.matchesObjectContext());
assertTrue(STRING_TYPE.matchesStringContext());
assertTrue(STRING_TYPE.matchesUint32Context());
// isNullable
assertFalse(STRING_TYPE.isNullable());
assertTrue(createNullableType(STRING_TYPE).isNullable());
// toString
assertEquals("string", STRING_TYPE.toString());
assertTrue(STRING_TYPE.hasDisplayName());
assertEquals("string", STRING_TYPE.getDisplayName());
// findPropertyType
assertTypeEquals(NUMBER_TYPE, STRING_TYPE.findPropertyType("length"));
assertEquals(null, STRING_TYPE.findPropertyType("unknownProperty"));
Asserts.assertResolvesToSame(STRING_TYPE);
assertFalse(STRING_TYPE.isNominalConstructor());
}
private void assertPropertyTypeDeclared(ObjectType ownerType, String prop) {
assertTrue(ownerType.isPropertyTypeDeclared(prop));
assertFalse(ownerType.isPropertyTypeInferred(prop));
}
private void assertPropertyTypeInferred(ObjectType ownerType, String prop) {
assertFalse(ownerType.isPropertyTypeDeclared(prop));
assertTrue(ownerType.isPropertyTypeInferred(prop));
}
private void assertPropertyTypeUnknown(ObjectType ownerType, String prop) {
assertFalse(ownerType.isPropertyTypeDeclared(prop));
assertFalse(ownerType.isPropertyTypeInferred(prop));
assertTrue(ownerType.getPropertyType(prop).isUnknownType());
}
private void assertReturnTypeEquals(JSType expectedReturnType,
JSType function) {
assertTrue(function instanceof FunctionType);
assertTypeEquals(expectedReturnType,
((FunctionType) function).getReturnType());
}
/**
* Tests the behavior of record types.
*/
public void testRecordType() throws Exception {
// isXxx
assertTrue(recordType.isObject());
assertFalse(recordType.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>isFunctionPrototypeType());
// canAssignTo
assertTrue(recordType.canAssignTo(ALL_TYPE));
assertFalse(recordType.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(recordType.canAssignTo(NUMBER_TYPE));
assertFalse(recordType.canAssignTo(DATE_TYPE));
assertFalse(recordType.canAssignTo(REGEXP_TYPE));
assertTrue(recordType.canAssignTo(UNKNOWN_TYPE));
assertTrue(recordType.canAssignTo(OBJECT_TYPE));
assertFalse(recordType.canAssignTo(U2U_CONSTRUCTOR_TYPE));
// autoboxesTo
assertNull(recordType.autoboxesTo());
// canBeCalled
assertFalse(recordType.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(recordType, ALL_TYPE);
assertCanTestForEqualityWith(recordType, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(recordType, recordType);
assertCanTestForEqualityWith(recordType, functionType);
assertCanTestForEqualityWith(recordType, OBJECT_TYPE);
assertCanTestForEqualityWith(recordType, NUMBER_TYPE);
assertCanTestForEqualityWith(recordType, DATE_TYPE);
assertCanTestForEqualityWith(recordType, REGEXP_TYPE);
// canTestForShallowEqualityWith
assertTrue(recordType.canTestForShallowEqualityWith(NO_TYPE));
assertTrue(recordType.canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(ARRAY_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(recordType.
canTestForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertTrue(recordType.canTestForShallowEqualityWith(recordType));
assertFalse(recordType.canTestForShallowEqualityWith(NULL_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(NUMBER_TYPE));
assertFalse(recordType.canTestFor
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>ShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertTrue(recordType.canTestForShallowEqualityWith(OBJECT_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertFalse(recordType.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(REGEXP_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(STRING_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(recordType.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(recordType.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(recordType.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// matchesXxx
assertFalse(recordType.matchesInt32Context());
assertFalse(recordType.matchesNumberContext());
assertTrue(recordType.matchesObjectContext());
assertFalse(recordType.matchesStringContext());
assertFalse(recordType.matchesUint32Context());
Asserts.assertResolvesToSame(recordType);
}
/**
* Tests the behavior of the instance of Function.
*/
public void testFunctionInstanceType() throws Exception {
FunctionType functionInst = FUNCTION_INSTANCE_TYPE;
// isXxx
assertTrue(functionInst.isObject());
assertFalse(functionInst.isFunctionPrototypeType());
assertTrue(functionInst.getImplicitPrototype()
.isFunctionPrototypeType());
// canAssignTo
assertTrue(functionInst.canAssignTo(ALL_TYPE));
assertFalse(functionInst.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(functionInst.canAssignTo(NUMBER_TYPE));
assertFalse(functionInst.canAssignTo(DATE_TYPE));
assertFalse(functionInst.canAssignTo(REGEXP_TYPE));
assertTrue(functionInst.canAssignTo(UNKNOWN_TYPE));
assertTrue(functionInst.canAssignTo(U2U_CONSTRUCTOR_TYPE));
// autoboxesTo
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> assertFalse(functionInst.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(functionInst.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(functionInst.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(functionInst.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(functionInst.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// matchesXxx
assertFalse(functionInst.matchesInt32Context());
assertFalse(functionInst.matchesNumberContext());
assertTrue(functionInst.matchesObjectContext());
assertFalse(functionInst.matchesStringContext());
assertFalse(functionInst.matchesUint32Context());
// hasProperty
assertTrue(functionInst.hasProperty("prototype"));
assertPropertyTypeInferred(functionInst, "prototype");
// misc
assertTypeEquals(FUNCTION_FUNCTION_TYPE, functionInst.getConstructor());
assertTypeEquals(FUNCTION_PROTOTYPE, functionInst.getImplicitPrototype());
assertTypeEquals(functionInst, FUNCTION_FUNCTION_TYPE.getInstanceType());
Asserts.assertResolvesToSame(functionInst);
}
/**
* Tests the behavior of functional types.
*/
public void testFunctionType() throws Exception {
// isXxx
assertTrue(functionType.isObject());
assertFalse(functionType.isFunctionPrototypeType());
assertTrue(functionType.getImplicitPrototype().getImplicitPrototype()
.isFunctionPrototypeType());
// canAssignTo
assertTrue(functionType.canAssignTo(ALL_TYPE));
assertFalse(functionType.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(functionType.canAssignTo(NUMBER_TYPE));
assertFalse(functionType.canAssignTo(DATE_TYPE));
assertFalse(functionType.canAssignTo(REGEXP_TYPE));
assertTrue(functionType.canAssignTo(UNKNOWN_TYPE));
assertTrue(functionType.canAssignTo(U2U_CONSTRUCTOR_TYPE));
// autoboxesTo
assertNull(functionType.autoboxesTo());
// canBeCalled
assertTrue(functionType.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(functionType, ALL_TYPE);
assertCanTestForEqualityWith(functionType, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(functionType, functionType);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(functionType.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// matchesXxx
assertFalse(functionType.matchesInt32Context());
assertFalse(functionType.matchesNumberContext());
assertTrue(functionType.matchesObjectContext());
assertFalse(functionType.matchesStringContext());
assertFalse(functionType.matchesUint32Context());
// hasProperty
assertTrue(functionType.hasProperty("prototype"));
assertPropertyTypeInferred(functionType, "prototype");
Asserts.assertResolvesToSame(functionType);
assertEquals("aFunctionName", new FunctionBuilder(registry).
withName("aFunctionName").build().getDisplayName());
}
/**
* Tests the subtyping relation of record types.
*/
public void testRecordTypeSubtyping() {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("a", NUMBER_TYPE, null);
builder.addProperty("b", STRING_TYPE, null);
builder.addProperty("c", STRING_TYPE, null);
JSType subRecordType = builder.build();
assertTrue(subRecordType.isSubtype(recordType));
assertFalse(recordType.isSubtype(subRecordType));
builder = new RecordTypeBuilder(registry);
builder.addProperty("a", OBJECT_TYPE, null);
builder.addProperty("b", STRING_TYPE, null);
JSType differentRecordType = builder.build();
assertFalse(differentRecordType.isSubtype(recordType));
assertFalse(recordType.isSubtype(differentRecordType));
}
/**
* Tests the subtyping relation of record types when an object has
* an inferred property..
*/
public void testRecordTypeSubtypingWithInferredProperties() {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("a", googSubBarInst, null);
JSType record = builder.build();
ObjectType subtypeProp = registry.createAnonymousObjectType();
subtypeProp.defineInferredProperty("a", googSubSubBarInst, null);
assertTrue(subtypeProp.isSubtype(record));
assertFalse(record.isSubtype(subtypeProp));
ObjectType supertypeProp = registry.createAnonymousObjectType();
supertypeProp.defineInferredProperty("a", googBarInst, null);
assertFalse(supertypeProp.isSubtype(record));
assertFalse(record.isSubtype(supertypeProp
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("a", STRING_TYPE, null);
JSType recordType = builder.build();
assertTypeEquals(NO_OBJECT_TYPE,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
// if Function is given a property "a" of type "string", then it's
// a subtype of the record type {a: string}.
U2U_CONSTRUCTOR_TYPE.defineDeclaredProperty("a", STRING_TYPE, null);
assertTypeEquals(U2U_CONSTRUCTOR_TYPE,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
assertTypeEquals(U2U_CONSTRUCTOR_TYPE,
U2U_CONSTRUCTOR_TYPE.getGreatestSubtype(recordType));
}
public void testRecordTypeGreatestSubType6() {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("x", UNKNOWN_TYPE, null);
JSType recordType = builder.build();
assertTypeEquals(NO_OBJECT_TYPE,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
// if Function is given a property "x" of type "string", then it's
// also a subtype of the record type {x: ?}.
U2U_CONSTRUCTOR_TYPE.defineDeclaredProperty("x", STRING_TYPE, null);
assertTypeEquals(U2U_CONSTRUCTOR_TYPE,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
assertTypeEquals(U2U_CONSTRUCTOR_TYPE,
U2U_CONSTRUCTOR_TYPE.getGreatestSubtype(recordType));
}
public void testRecordTypeGreatestSubType7() {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("x", NUMBER_TYPE, null);
JSType recordType = builder.build();
// if Function is given a property "x" of type "string", then it's
// not a subtype of the record type {x: number}.
U2U_CONSTRUCTOR_TYPE.defineDeclaredProperty("x", STRING_TYPE, null);
assertTypeEquals(NO_OBJECT_TYPE,
recordType.getGreatestSubtype(U2U
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>_CONSTRUCTOR_TYPE));
}
public void testRecordTypeGreatestSubType8() {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("xyz", UNKNOWN_TYPE, null);
JSType recordType = builder.build();
assertTypeEquals(NO_OBJECT_TYPE,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
// if goog.Bar is given a property "xyz" of type "string", then it's
// also a subtype of the record type {x: ?}.
googBar.defineDeclaredProperty("xyz", STRING_TYPE, null);
assertTypeEquals(googBar,
recordType.getGreatestSubtype(U2U_CONSTRUCTOR_TYPE));
assertTypeEquals(googBar,
U2U_CONSTRUCTOR_TYPE.getGreatestSubtype(recordType));
ObjectType googBarInst = googBar.getInstanceType();
assertTypeEquals(NO_OBJECT_TYPE,
recordType.getGreatestSubtype(googBarInst));
assertTypeEquals(NO_OBJECT_TYPE,
googBarInst.getGreatestSubtype(recordType));
}
/**
* Tests the "apply" method on the function type.
*/
public void testApplyOfDateMethod() {
JSType applyType = dateMethod.getPropertyType("apply");
assertTrue("apply should be a function",
applyType instanceof FunctionType);
FunctionType applyFn = (FunctionType) applyType;
assertTypeEquals("apply should have the same return type as its function",
NUMBER_TYPE, applyFn.getReturnType());
Node params = applyFn.getParametersNode();
assertEquals("apply takes two args",
2, params.getChildCount());
assertTypeEquals("apply's first arg is the @this type",
registry.createOptionalNullableType(DATE_TYPE),
params.getFirstChild().getJSType());
assertTypeEquals("apply's second arg is an Array",
registry.createOptionalNullableType(OBJECT_TYPE),
params.getLastChild().getJSType());
assertTrue("apply's args must be optional",
params.getFirstChild().isOptionalArg());
assertTrue("apply's args must be optional",
params.getLastChild().isOptionalArg());
}
/**
* Tests the "call" method on the function type.
*/
public void testCallOf
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>isAllType());
assertFalse(BOOLEAN_TYPE.isVoidType());
assertFalse(BOOLEAN_TYPE.isConstructor());
assertFalse(BOOLEAN_TYPE.isInstanceType());
// autoboxesTo
assertTypeEquals(BOOLEAN_OBJECT_TYPE, BOOLEAN_TYPE.autoboxesTo());
// unboxesTo
assertTypeEquals(BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE.unboxesTo());
// canAssignTo
assertTrue(BOOLEAN_TYPE.canAssignTo(ALL_TYPE));
assertFalse(BOOLEAN_TYPE.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canAssignTo(NUMBER_TYPE));
assertFalse(BOOLEAN_TYPE.canAssignTo(functionType));
assertFalse(BOOLEAN_TYPE.canAssignTo(NULL_TYPE));
assertFalse(BOOLEAN_TYPE.canAssignTo(OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canAssignTo(DATE_TYPE));
assertTrue(BOOLEAN_TYPE.canAssignTo(unresolvedNamedType));
assertFalse(BOOLEAN_TYPE.canAssignTo(namedGoogBar));
assertFalse(BOOLEAN_TYPE.canAssignTo(REGEXP_TYPE));
// canBeCalled
assertFalse(BOOLEAN_TYPE.canBeCalled());
// canTestForEqualityWith
assertCanTestForEqualityWith(BOOLEAN_TYPE, ALL_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, STRING_OBJECT_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, NUMBER_TYPE);
assertCannotTestForEqualityWith(BOOLEAN_TYPE, functionType);
assertCannotTestForEqualityWith(BOOLEAN_TYPE, VOID_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, OBJECT_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, DATE_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, REGEXP_TYPE);
assertCanTestForEqualityWith(BOOLEAN_TYPE, UNKNOWN_TYPE);
// canTestForShallowEqualityWith
assertTrue(BOOLEAN_TYPE.canTestForShallowEqualityWith(NO_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(NO_OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(ARRAY_TYPE));
assertTrue(BOOLEAN_TYPE.canTestForShallowEqualityWith(BOOLEAN_TYPE));
assertFalse(BOOLEAN_TYPE.
canTest
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>ForShallowEqualityWith(BOOLEAN_OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(DATE_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(EVAL_ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(functionType));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(NULL_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(NUMBER_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(NUMBER_OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(URI_ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(RANGE_ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.
canTestForShallowEqualityWith(REFERENCE_ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(REGEXP_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(STRING_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(STRING_OBJECT_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(SYNTAX_ERROR_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(TYPE_ERROR_TYPE));
assertTrue(BOOLEAN_TYPE.canTestForShallowEqualityWith(ALL_TYPE));
assertFalse(BOOLEAN_TYPE.canTestForShallowEqualityWith(VOID_TYPE));
assertTrue(BOOLEAN_TYPE.canTestForShallowEqualityWith(UNKNOWN_TYPE));
// isNullable
assertFalse(BOOLEAN_TYPE.isNullable());
// matchesXxx
assertTrue(BOOLEAN_TYPE.matchesInt32Context());
assertTrue(BOOLEAN_TYPE.matchesNumberContext());
assertTrue(BOOLEAN_TYPE.matchesObjectContext());
assertTrue(BOOLEAN_TYPE.matchesStringContext());
assertTrue(BOOLEAN_TYPE.matchesUint32Context());
// toString
assertEquals("boolean", BOOLEAN_TYPE.toString());
assertTrue(BOOLEAN_TYPE.hasDisplayName());
assertEquals("boolean", BOOLEAN_TYPE.getDisplayName());
Asserts.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> elementsType.toString());
assertTrue(elementsType.hasDisplayName());
assertEquals("Enum", elementsType.getDisplayName());
Asserts.assertResolvesToSame(elementsType);
}
public void testStringEnumType() throws Exception {
EnumElementType stringEnum =
new EnumType(registry, "Enum", null, STRING_TYPE).getElementsType();
assertTypeEquals(UNKNOWN_TYPE, stringEnum.getPropertyType("length"));
assertTypeEquals(NUMBER_TYPE, stringEnum.findPropertyType("length"));
assertEquals(false, stringEnum.hasProperty("length"));
assertTypeEquals(STRING_OBJECT_TYPE, stringEnum.autoboxesTo());
assertNull(stringEnum.getConstructor());
Asserts.assertResolvesToSame(stringEnum);
}
public void testStringObjectEnumType() throws Exception {
EnumElementType stringEnum =
new EnumType(registry, "Enum", null, STRING_OBJECT_TYPE)
.getElementsType();
assertTypeEquals(NUMBER_TYPE, stringEnum.getPropertyType("length"));
assertTypeEquals(NUMBER_TYPE, stringEnum.findPropertyType("length"));
assertEquals(true, stringEnum.hasProperty("length"));
assertTypeEquals(STRING_OBJECT_FUNCTION_TYPE, stringEnum.getConstructor());
}
/**
* Tests object types.
*/
public void testObjectType() throws Exception {
PrototypeObjectType objectType =
new PrototypeObjectType(registry, null, null);
// isXxx
assertFalse(objectType.isAllType());
assertFalse(objectType.isArrayType());
assertFalse(objectType.isDateType());
assertFalse(objectType.isFunctionPrototypeType());
assertTrue(objectType.getImplicitPrototype() == OBJECT_TYPE);
// canAssignTo
assertTrue(objectType.canAssignTo(ALL_TYPE));
assertFalse(objectType.canAssignTo(STRING_OBJECT_TYPE));
assertFalse(objectType.canAssignTo(NUMBER_TYPE));
assertFalse(objectType.canAssignTo(functionType));
assertFalse(objectType.canAssignTo(NULL_TYPE));
assertFalse(objectType.canAssignTo(DATE_TYPE));
assertTrue(objectType.canAssignTo(OBJECT_TYPE));
assertTrue(objectType.canAssignTo(unresolvedNamedType));
assertFalse(objectType.canAssignTo(namedGoogBar));
assertFalse(object
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> URIError
assertTypeEquals(
URI_ERROR_FUNCTION_TYPE, URI_ERROR_TYPE.getConstructor());
}
/**
* Tests that the method {@link JSType#canTestForEqualityWith(JSType)} handles
* special corner cases.
*/
@SuppressWarnings("checked")
public void testCanTestForEqualityWithCornerCases() {
// null == undefined is always true
assertCannotTestForEqualityWith(NULL_TYPE, VOID_TYPE);
// (Object,null) == undefined could be true or false
UnionType nullableObject =
(UnionType) createUnionType(OBJECT_TYPE, NULL_TYPE);
assertCanTestForEqualityWith(nullableObject, VOID_TYPE);
assertCanTestForEqualityWith(VOID_TYPE, nullableObject);
}
/**
* Tests the {@link JSType#testForEquality(JSType)} method.
*/
public void testTestForEquality() {
compare(TRUE, NO_OBJECT_TYPE, NO_OBJECT_TYPE);
compare(UNKNOWN, ALL_TYPE, ALL_TYPE);
compare(TRUE, NO_TYPE, NO_TYPE);
compare(UNKNOWN, NO_RESOLVED_TYPE, NO_RESOLVED_TYPE);
compare(UNKNOWN, NO_OBJECT_TYPE, NUMBER_TYPE);
compare(UNKNOWN, ALL_TYPE, NUMBER_TYPE);
compare(UNKNOWN, NO_TYPE, NUMBER_TYPE);
compare(FALSE, NULL_TYPE, BOOLEAN_TYPE);
compare(TRUE, NULL_TYPE, NULL_TYPE);
compare(FALSE, NULL_TYPE, NUMBER_TYPE);
compare(FALSE, NULL_TYPE, OBJECT_TYPE);
compare(FALSE, NULL_TYPE, STRING_TYPE);
compare(TRUE, NULL_TYPE, VOID_TYPE);
compare(UNKNOWN, NULL_TYPE, createUnionType(UNKNOWN_TYPE, VOID_TYPE));
compare(UNKNOWN, NULL_TYPE, createUnionType(OBJECT_TYPE, VOID_TYPE));
compare(UNKNOWN, NULL_TYPE, unresolvedNamedType);
compare(UNKNOWN,
NULL_TYPE, createUnionType(unresolvedNamedType, DATE_TYPE));
compare(FALSE, VOID_TYPE, REGEXP_TYPE);
compare(TRUE, VOID_TYPE, VOID_TYPE);
compare(UNKNOWN, VOID_TYPE, createUnionType(REGEXP_TYPE, VOID_TYPE
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>));
compare(UNKNOWN, NUMBER_TYPE, BOOLEAN_TYPE);
compare(UNKNOWN, NUMBER_TYPE, NUMBER_TYPE);
compare(UNKNOWN, NUMBER_TYPE, OBJECT_TYPE);
compare(UNKNOWN, ARRAY_TYPE, BOOLEAN_TYPE);
compare(UNKNOWN, OBJECT_TYPE, BOOLEAN_TYPE);
compare(UNKNOWN, OBJECT_TYPE, STRING_TYPE);
compare(UNKNOWN, STRING_TYPE, STRING_TYPE);
compare(UNKNOWN, STRING_TYPE, BOOLEAN_TYPE);
compare(UNKNOWN, STRING_TYPE, NUMBER_TYPE);
compare(FALSE, STRING_TYPE, VOID_TYPE);
compare(FALSE, STRING_TYPE, NULL_TYPE);
compare(FALSE, STRING_TYPE, createUnionType(NULL_TYPE, VOID_TYPE));
compare(UNKNOWN, UNKNOWN_TYPE, BOOLEAN_TYPE);
compare(UNKNOWN, UNKNOWN_TYPE, NULL_TYPE);
compare(UNKNOWN, UNKNOWN_TYPE, VOID_TYPE);
compare(FALSE, U2U_CONSTRUCTOR_TYPE, BOOLEAN_TYPE);
compare(FALSE, U2U_CONSTRUCTOR_TYPE, NUMBER_TYPE);
compare(FALSE, U2U_CONSTRUCTOR_TYPE, STRING_TYPE);
compare(FALSE, U2U_CONSTRUCTOR_TYPE, VOID_TYPE);
compare(FALSE, U2U_CONSTRUCTOR_TYPE, NULL_TYPE);
compare(UNKNOWN, U2U_CONSTRUCTOR_TYPE, OBJECT_TYPE);
compare(UNKNOWN, U2U_CONSTRUCTOR_TYPE, ALL_TYPE);
compare(UNKNOWN, NULL_TYPE, subclassOfUnresolvedNamedType);
JSType functionAndNull = createUnionType(NULL_TYPE, dateMethod);
compare(UNKNOWN, functionAndNull, dateMethod);
compare(UNKNOWN, NULL_TYPE, NO_TYPE);
compare(UNKNOWN, VOID_TYPE, NO_TYPE);
compare(UNKNOWN, NULL_TYPE, unresolvedNamedType);
compare(UNKNOWN, VOID_TYPE, unresolvedNamedType);
compare(TRUE, NO_TYPE, NO_TYPE);
}
private void compare(TernaryValue r, JSType t1, JSType t2) {
assertEquals(r, t1.testForEquality(t2));
assertEquals(r, t2.testForEquality(t1));
}
private void assertCanTestForEqualityWith(JS
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f1));
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f2));
}
public void testSubtypingFunctionFixedArgsNotMatching() throws Exception {
FunctionType f1 = registry.createFunctionType(OBJECT_TYPE,
false, EVAL_ERROR_TYPE, UNKNOWN_TYPE);
FunctionType f2 = registry.createFunctionType(STRING_OBJECT_TYPE,
false, ERROR_TYPE, ALL_TYPE);
assertTrue(f1.isSubtype(f1));
assertFalse(f1.isSubtype(f2));
assertTrue(f2.isSubtype(f1));
assertTrue(f2.isSubtype(f2));
assertTrue(f1.isSubtype(U2U_CONSTRUCTOR_TYPE));
assertTrue(f2.isSubtype(U2U_CONSTRUCTOR_TYPE));
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f1));
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f2));
}
public void testSubtypingFunctionVariableArgsOneOnly() throws Exception {
// f1 = (EvalError...) -> Object
FunctionType f1 = registry.createFunctionType(OBJECT_TYPE,
true, EVAL_ERROR_TYPE);
// f2 = (Error, Object) -> String
FunctionType f2 = registry.createFunctionType(STRING_OBJECT_TYPE,
false, ERROR_TYPE, OBJECT_TYPE);
assertTrue(f1.isSubtype(f1));
assertFalse(f1.isSubtype(f2));
assertFalse(f2.isSubtype(f1));
assertTrue(f2.isSubtype(f2));
assertTrue(f1.isSubtype(U2U_CONSTRUCTOR_TYPE));
assertTrue(f2.isSubtype(U2U_CONSTRUCTOR_TYPE));
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f1));
assertTrue(U2U_CONSTRUCTOR_TYPE.isSubtype(f2));
}
public void testSubtypingFunctionVariableArgsBoth() throws Exception {
// f1 = (UriError, EvalError, EvalError...) -> Object
FunctionType f1 = registry.createFunctionType(OBJECT_TYPE,
true, URI_ERROR_TYPE, EVAL_ERROR_TYPE, E
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>7));
assertTrue(LEAST_FUNCTION_TYPE.isSubtype(f8));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f1));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f2));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f3));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f4));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f5));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f6));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f7));
assertFalse(GREATEST_FUNCTION_TYPE.isSubtype(f8));
}
/**
* Types to test for symmetrical relationships.
*/
private List<JSType> getTypesToTestForSymmetry() {
return Lists.newArrayList(
UNKNOWN_TYPE,
NULL_TYPE,
VOID_TYPE,
NUMBER_TYPE,
STRING_TYPE,
BOOLEAN_TYPE,
OBJECT_TYPE,
U2U_CONSTRUCTOR_TYPE,
LEAST_FUNCTION_TYPE,
GREATEST_FUNCTION_TYPE,
ALL_TYPE,
NO_TYPE,
NO_OBJECT_TYPE,
NO_RESOLVED_TYPE,
createUnionType(BOOLEAN_TYPE, STRING_TYPE),
createUnionType(NUMBER_TYPE, STRING_TYPE),
createUnionType(NULL_TYPE, dateMethod),
createUnionType(UNKNOWN_TYPE, dateMethod),
createUnionType(namedGoogBar, dateMethod),
createUnionType(NULL_TYPE, unresolvedNamedType),
enumType,
elementsType,
dateMethod,
functionType,
unresolvedNamedType,
googBar,
namedGoogBar,
googBar.getInstanceType(),
namedGoogBar,
subclassOfUnresolvedNamedType,
subclassCtor,
recordType,
forwardDeclaredNamedType,
createUnionType(forwardDeclaredNamedType, NULL_TYPE));
}
public void testSymmetryOfTestForEquality() {
List<JSType> listA = getTypesToTestForSymmetry();
List<JSType> listB = getTypesToTestForSymmetry();
for (JSType typeA : listA) {
for (JSType typeB : listB
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>)",
expected.toString());
}
public void testLeastSupertypeUnresolvedNamedType2() {
JSType expected = registry.createUnionType(
unresolvedNamedType, UNKNOWN_TYPE);
assertTypeEquals(expected,
unresolvedNamedType.getLeastSupertype(UNKNOWN_TYPE));
assertTypeEquals(expected,
UNKNOWN_TYPE.getLeastSupertype(unresolvedNamedType));
assertTypeEquals(UNKNOWN_TYPE, expected);
}
public void testLeastSupertypeUnresolvedNamedType3() {
JSType expected = registry.createUnionType(
unresolvedNamedType, CHECKED_UNKNOWN_TYPE);
assertTypeEquals(expected,
unresolvedNamedType.getLeastSupertype(CHECKED_UNKNOWN_TYPE));
assertTypeEquals(expected,
CHECKED_UNKNOWN_TYPE.getLeastSupertype(unresolvedNamedType));
assertTypeEquals(CHECKED_UNKNOWN_TYPE, expected);
}
/** Tests the subclass of an unresolved named type */
public void testSubclassOfUnresolvedNamedType() {
assertTrue(subclassOfUnresolvedNamedType.isUnknownType());
}
/**
* Tests that Proxied FunctionTypes behave the same over getLeastSupertype and
* getGreatestSubtype as non proxied FunctionTypes
*/
public void testSupertypeOfProxiedFunctionTypes() {
ObjectType fn1 =
new FunctionBuilder(registry)
.withParamsNode(new Node(Token.PARAM_LIST))
.withReturnType(NUMBER_TYPE)
.build();
ObjectType fn2 =
new FunctionBuilder(registry)
.withParamsNode(new Node(Token.PARAM_LIST))
.withReturnType(STRING_TYPE)
.build();
ObjectType p1 = new ProxyObjectType(registry, fn1);
ObjectType p2 = new ProxyObjectType(registry, fn2);
ObjectType supremum =
new FunctionBuilder(registry)
.withParamsNode(new Node(Token.PARAM_LIST))
.withReturnType(registry.createUnionType(STRING_TYPE, NUMBER_TYPE))
.build();
assertTypeEquals(fn1.getLeastSupertype(fn2), p1.getLeastSupertype(p2));
assertTypeEquals(supremum, fn1.getLeastSupertype(fn2));
assertTypeEquals(supremum, fn1.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(a.isResolved());
assertTrue(b.isResolved());
assertEquals(a.hashCode(), realA.hashCode());
assertTypeEquals(a, realA);
assertEquals(b.hashCode(), realB.hashCode());
assertTypeEquals(b, realB);
JSType resolvedA = Asserts.assertValidResolve(a);
assertNotSame(resolvedA, a);
assertSame(resolvedA, realA);
JSType resolvedB = Asserts.assertValidResolve(b);
assertNotSame(resolvedB, b);
assertSame(resolvedB, realB);
}
/**
* Tests the {@link NamedType#equals} function against other types
* when it's forward-declared.
*/
public void testForwardDeclaredNamedTypeEquals() {
// test == if references are equal
NamedType a = new NamedType(registry, "typeA", "source", 1, 0);
NamedType b = new NamedType(registry, "typeA", "source", 1, 0);
registry.forwardDeclareType("typeA");
assertEquals(a.hashCode(), b.hashCode());
assertTypeEquals(a, b);
a.resolve(null, EMPTY_SCOPE);
assertTrue(a.isResolved());
assertFalse(b.isResolved());
assertEquals(a.hashCode(), b.hashCode());
assertTypeEquals(a, b);
assertFalse(a.isEquivalentTo(UNKNOWN_TYPE));
assertFalse(b.isEquivalentTo(UNKNOWN_TYPE));
assertTrue(a.isEmptyType());
assertFalse(a.isNoType());
assertTrue(a.isNoResolvedType());
}
public void testForwardDeclaredNamedType() {
NamedType a = new NamedType(registry, "typeA", "source", 1, 0);
registry.forwardDeclareType("typeA");
assertTypeEquals(UNKNOWN_TYPE, a.getLeastSupertype(UNKNOWN_TYPE));
assertTypeEquals(CHECKED_UNKNOWN_TYPE,
a.getLeastSupertype(CHECKED_UNKNOWN_TYPE));
assertTypeEquals(UNKNOWN_TYPE, UNKNOWN_TYPE.getLeastSupertype(a));
assertTypeEquals(CHECKED_UNKNOWN_TYPE,
CHECKED_UNKNOWN_TYPE.getLeastSupertype(a));
}
/**
* Tests {@link JSType#getGreatestSubtype
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(JSType)} on simple types.
*/
public void testGreatestSubtypeSimpleTypes() {
assertTypeEquals(ARRAY_TYPE,
ARRAY_TYPE.getGreatestSubtype(ALL_TYPE));
assertTypeEquals(ARRAY_TYPE,
ALL_TYPE.getGreatestSubtype(ARRAY_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
REGEXP_TYPE.getGreatestSubtype(NO_OBJECT_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
NO_OBJECT_TYPE.getGreatestSubtype(REGEXP_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
ARRAY_TYPE.getGreatestSubtype(STRING_OBJECT_TYPE));
assertTypeEquals(NO_TYPE, ARRAY_TYPE.getGreatestSubtype(NUMBER_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
ARRAY_TYPE.getGreatestSubtype(functionType));
assertTypeEquals(STRING_OBJECT_TYPE,
STRING_OBJECT_TYPE.getGreatestSubtype(OBJECT_TYPE));
assertTypeEquals(STRING_OBJECT_TYPE,
OBJECT_TYPE.getGreatestSubtype(STRING_OBJECT_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
ARRAY_TYPE.getGreatestSubtype(DATE_TYPE));
assertTypeEquals(NO_OBJECT_TYPE,
ARRAY_TYPE.getGreatestSubtype(REGEXP_TYPE));
assertTypeEquals(EVAL_ERROR_TYPE,
ERROR_TYPE.getGreatestSubtype(EVAL_ERROR_TYPE));
assertTypeEquals(EVAL_ERROR_TYPE,
EVAL_ERROR_TYPE.getGreatestSubtype(ERROR_TYPE));
assertTypeEquals(NO_TYPE,
NULL_TYPE.getGreatestSubtype(ERROR_TYPE));
assertTypeEquals(UNKNOWN_TYPE,
NUMBER_TYPE.getGreatestSubtype(UNKNOWN_TYPE));
assertTypeEquals(NO_RESOLVED_TYPE,
NO_OBJECT_TYPE.getGreatestSubtype(forwardDeclaredNamedType));
assertTypeEquals(NO_RESOLVED_TYPE,
forwardDeclaredNamedType.getGreatestSubtype(NO_OBJECT_TYPE));
}
/**
* Tests that a derived class extending a type via a named type is a subtype
* of it.
*/
public void testSubtypingDerivedExtendsNamedBaseType() throws Exception {
ObjectType derived =
registry
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>NativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE));
verifySubtypeChain(typeChain);
}
public void testRecordAndObjectChain2() throws Exception {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("date", DATE_TYPE, null);
JSType hasDateProperty = builder.build();
List<JSType> typeChain = Lists.newArrayList(
registry.getNativeType(JSTypeNative.OBJECT_TYPE),
hasDateProperty,
googBar.getInstanceType(),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE));
verifySubtypeChain(typeChain);
}
public void testRecordAndObjectChain3() throws Exception {
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
builder.addProperty("date", UNKNOWN_TYPE, null);
JSType hasUnknownDateProperty = builder.build();
List<JSType> typeChain = Lists.newArrayList(
registry.getNativeType(JSTypeNative.OBJECT_TYPE),
hasUnknownDateProperty,
googBar.getInstanceType(),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE));
verifySubtypeChain(typeChain);
}
public void testNullableNamedTypeChain() throws Exception {
List<JSType> typeChain = Lists.newArrayList(
registry.getNativeType(JSTypeNative.ALL_TYPE),
registry.createOptionalNullableType(
registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE)),
registry.createOptionalNullableType(
registry.getNativeType(JSTypeNative.OBJECT_TYPE)),
registry.createOptionalNullableType(googBar.getPrototype()),
registry.createOptionalNullableType(googBar.getInstanceType()),
registry.createNullableType(googSubBar.getPrototype()),
registry.createNullableType(googSubBar.getInstanceType()),
googSubSubBar.getPrototype(),
googSubSubBar.getInstanceType(),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE));
verifySubtypeChain(typeChain);
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>RestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(BOOLEAN_TYPE,
BOOLEAN_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(NO_TYPE,
NULL_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NULL_TYPE,
NULL_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(NUMBER_TYPE,
NUMBER_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NUMBER_TYPE,
NUMBER_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(STRING_TYPE,
STRING_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(STRING_TYPE,
STRING_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(STRING_OBJECT_TYPE,
STRING_OBJECT_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NO_TYPE,
STRING_OBJECT_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(NO_TYPE,
VOID_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(VOID_TYPE,
VOID_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(NO_OBJECT_TYPE,
NO_OBJECT_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NO_TYPE,
NO_OBJECT_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(NO_TYPE,
NO_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NO_TYPE,
NO_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(ALL_TYPE,
ALL_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
assertTypeEquals(CHECKED_UNKNOWN_TYPE,
UNKNOWN_TYPE.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(UNKNOWN_TYPE,
UNKNOWN_TYPE.getRestrictedTypeGivenToBooleanOutcome(false));
// unions
UnionType nullableStringValue =
(UnionType) createNullableType(STRING_TYPE);
assertTypeEquals(STRING
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>_TYPE,
nullableStringValue.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(nullableStringValue,
nullableStringValue.getRestrictedTypeGivenToBooleanOutcome(false));
UnionType nullableStringObject =
(UnionType) createNullableType(STRING_OBJECT_TYPE);
assertTypeEquals(STRING_OBJECT_TYPE,
nullableStringObject.getRestrictedTypeGivenToBooleanOutcome(true));
assertTypeEquals(NULL_TYPE,
nullableStringObject.getRestrictedTypeGivenToBooleanOutcome(false));
}
public void testRegisterProperty() {
int i = 0;
List<JSType> allObjects = Lists.newArrayList();
for (JSType type : types) {
String propName = "ALF" + i++;
if (type instanceof ObjectType) {
ObjectType objType = (ObjectType) type;
objType.defineDeclaredProperty(propName, UNKNOWN_TYPE, null);
objType.defineDeclaredProperty("allHaz", UNKNOWN_TYPE, null);
assertTypeEquals(type,
registry.getGreatestSubtypeWithProperty(type, propName));
List<JSType> typesWithProp =
Lists.newArrayList(registry.getTypesWithProperty(propName));
String message = type.toString();
assertEquals(message, 1, typesWithProp.size());
assertTypeEquals(type, typesWithProp.get(0));
assertTypeEquals(NO_TYPE,
registry.getGreatestSubtypeWithProperty(type, "GRRR"));
allObjects.add(type);
}
}
assertTypeListEquals(registry.getTypesWithProperty("GRRR"),
Lists.newArrayList(NO_TYPE));
assertTypeListEquals(allObjects,
registry.getTypesWithProperty("allHaz"));
}
public void testRegisterPropertyMemoization() {
ObjectType derived1 = registry.createObjectType("d1", null, namedGoogBar);
ObjectType derived2 = registry.createObjectType("d2", null, namedGoogBar);
derived1.defineDeclaredProperty("propz", UNKNOWN_TYPE, null);
assertTypeEquals(derived1,
registry.getGreatestSubtypeWithProperty(derived1, "propz"));
assertTypeEquals(NO_OBJECT_TYPE,
registry.getGreatestSubtypeWithProperty(derived2, "propz"));
derived2.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>defineDeclaredProperty("propz", UNKNOWN_TYPE, null);
assertTypeEquals(derived1,
registry.getGreatestSubtypeWithProperty(derived1, "propz"));
assertTypeEquals(derived2,
registry.getGreatestSubtypeWithProperty(derived2, "propz"));
}
/**
* Tests
* {@link JSTypeRegistry#getGreatestSubtypeWithProperty(JSType, String)}.
*/
public void testGreatestSubtypeWithProperty() {
ObjectType foo = registry.createObjectType("foo", null, OBJECT_TYPE);
ObjectType bar = registry.createObjectType("bar", null, namedGoogBar);
foo.defineDeclaredProperty("propz", UNKNOWN_TYPE, null);
bar.defineDeclaredProperty("propz", UNKNOWN_TYPE, null);
assertTypeEquals(bar,
registry.getGreatestSubtypeWithProperty(namedGoogBar, "propz"));
}
public void testGoodSetPrototypeBasedOn() {
FunctionType fun = registry.createConstructorType("fun", null, null, null);
fun.setPrototypeBasedOn(unresolvedNamedType);
assertTrue(fun.getInstanceType().isUnknownType());
}
public void testLateSetPrototypeBasedOn() {
FunctionType fun = registry.createConstructorType("fun", null, null, null);
assertFalse(fun.getInstanceType().isUnknownType());
fun.setPrototypeBasedOn(unresolvedNamedType);
assertTrue(fun.getInstanceType().isUnknownType());
}
public void testGetTypeUnderEquality1() {
for (JSType type : types) {
testGetTypeUnderEquality(type, type, type, type);
}
}
public void testGetTypesUnderEquality2() {
// objects can be equal to numbers
testGetTypeUnderEquality(
NUMBER_TYPE, OBJECT_TYPE,
NUMBER_TYPE, OBJECT_TYPE);
}
public void testGetTypesUnderEquality3() {
// null == undefined
testGetTypeUnderEquality(
NULL_TYPE, VOID_TYPE,
NULL_TYPE, VOID_TYPE);
}
@SuppressWarnings("checked")
public void testGetTypesUnderEquality4() {
// (number,string) and number/string
UnionType stringNumber =
(UnionType) createUnionType(NUMBER_TYPE, STRING_TYPE);
testGetTypeUnderEquality(
stringNumber, STRING_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>Deprecated(true);
assertNull(namedGoogBar.getOwnPropertyJSDocInfo("X"));
namedGoogBar.setPropertyJSDocInfo("X", info);
assertTrue(namedGoogBar.getOwnPropertyJSDocInfo("X").isDeprecated());
assertPropertyTypeInferred(namedGoogBar, "X");
assertTypeEquals(UNKNOWN_TYPE, namedGoogBar.getPropertyType("X"));
}
public void testGetAndSetJSDocInfoWithObjectTypes() throws Exception {
ObjectType sup =
registry.createObjectType(registry.createAnonymousObjectType());
ObjectType sub = registry.createObjectType(sup);
JSDocInfo deprecated = new JSDocInfo();
deprecated.setDeprecated(true);
JSDocInfo privateInfo = new JSDocInfo();
privateInfo.setVisibility(Visibility.PRIVATE);
sup.defineProperty("X", NUMBER_TYPE, true, null);
sup.setPropertyJSDocInfo("X", privateInfo);
sub.defineProperty("X", NUMBER_TYPE, true, null);
sub.setPropertyJSDocInfo("X", deprecated);
assertFalse(sup.getOwnPropertyJSDocInfo("X").isDeprecated());
assertEquals(Visibility.PRIVATE,
sup.getOwnPropertyJSDocInfo("X").getVisibility());
assertTypeEquals(NUMBER_TYPE, sup.getPropertyType("X"));
assertTrue(sub.getOwnPropertyJSDocInfo("X").isDeprecated());
assertNull(sub.getOwnPropertyJSDocInfo("X").getVisibility());
assertTypeEquals(NUMBER_TYPE, sub.getPropertyType("X"));
}
public void testGetAndSetJSDocInfoWithNoType() throws Exception {
JSDocInfo deprecated = new JSDocInfo();
deprecated.setDeprecated(true);
NO_TYPE.setPropertyJSDocInfo("X", deprecated);
assertNull(NO_TYPE.getOwnPropertyJSDocInfo("X"));
}
public void testObjectGetSubTypes() throws Exception {
assertTrue(
containsType(
OBJECT_FUNCTION_TYPE.getSubTypes(), googBar));
assertTrue(
containsType(
googBar.getSubTypes(), googSubBar));
assertFalse(
containsType(
googBar.getSubTypes(), googSubSubBar));
assertFalse(
containsType(
googSubBar.getSubTypes(), googSubBar));
assertTrue(
containsType(
googSubBar.getSubTypes
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>Name, int lineno, int charno) {
super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
Preconditions.checkNotNull(reference);
this.reference = reference;
this.sourceName = sourceName;
this.lineno = lineno;
this.charno = charno;
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, Node propertyNode) {
if (!isResolved()) {
// If this is an unresolved object type, we need to save all its
// properties and define them when it is resolved.
if (propertyContinuations == null) {
propertyContinuations = Lists.newArrayList();
}
propertyContinuations.add(
new PropertyContinuation(
propertyName, type, inferred, propertyNode));
return true;
} else {
return super.defineProperty(
propertyName, type, inferred, propertyNode);
}
}
private void finishPropertyContinuations() {
ObjectType referencedObjType = getReferencedObjTypeInternal();
if (referencedObjType != null && !referencedObjType.isUnknownType()) {
if (propertyContinuations != null) {
for (PropertyContinuation c : propertyContinuations) {
c.commit(this);
}
}
}
propertyContinuations = null;
}
/** Returns the type to which this refers (which is unknown if unresolved). */
public JSType getReferencedType() {
return getReferencedTypeInternal();
}
@Override
public String getReferenceName() {
return reference;
}
@Override
String toStringHelper(boolean forAnnotations) {
return reference;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
boolean isNamedType() {
return true;
}
@Override
public boolean isNominalType() {
return true;
}
/**
* Two named types are equivalent if they are the same {@code
* ObjectType} object. This is complicated by the fact that isEquivalent
* is sometimes called before we have a chance to resolve the type
* names.
*
* @return {@code true} iff {@code that} == {@code this} or {@code that}
* is a {@link NamedType} whose reference is the same as ours,
* or {@code that} is the type we reference
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
if (value == null) {
return null;
}
// resolving component by component
for (int i = 1; i < componentNames.length; i++) {
ObjectType parentClass = ObjectType.cast(value);
if (parentClass == null) {
return null;
}
if (componentNames[i].length() == 0) {
return null;
}
value = parentClass.getPropertyType(componentNames[i]);
}
return value;
}
private void setReferencedAndResolvedType(JSType type, ErrorReporter t,
StaticScope<JSType> enclosing) {
if (validator != null) {
validator.apply(type);
}
setReferencedType(type);
checkEnumElementCycle(t);
setResolvedTypeInternal(getReferencedType());
}
private void handleTypeCycle(ErrorReporter t) {
setReferencedType(
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
t.warning("Cycle detected in inheritance chain of type " + reference,
sourceName, lineno, charno);
setResolvedTypeInternal(getReferencedType());
}
private void checkEnumElementCycle(ErrorReporter t) {
JSType referencedType = getReferencedType();
if (referencedType instanceof EnumElementType &&
((EnumElementType) referencedType).getPrimitiveType() == this) {
handleTypeCycle(t);
}
}
// Warns about this type being unresolved iff it's not a forward-declared
// type name.
private void handleUnresolvedType(
ErrorReporter t, boolean ignoreForwardReferencedTypes) {
if (registry.isLastGeneration()) {
boolean isForwardDeclared =
ignoreForwardReferencedTypes &&
registry.isForwardDeclaredType(reference);
if (!isForwardDeclared && registry.isLastGeneration()) {
t.warning("Bad type annotation. Unknown type " + reference,
sourceName, lineno, charno);
} else {
setReferencedType(
registry.getNativeObjectType(
JSTypeNative.NO_RESOLVED_TYPE));
if (registry.isLastGeneration() && validator != null) {
validator.apply(getReferencedType());
}
}
setResolvedTypeInternal(getReferencedType());
} else {
setResolvedTypeInternal(this);
}
}
JSType getTypedefType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
public JSTypeSystem(AbstractCompiler compiler) {
registry = compiler.getTypeRegistry();
invalidatingTypes = Sets.newHashSet(
registry.getNativeType(JSTypeNative.ALL_TYPE),
registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE),
registry.getNativeType(JSTypeNative.NO_TYPE),
registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE),
registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE),
registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE),
registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE),
registry.getNativeType(JSTypeNative.UNKNOWN_TYPE));
}
@Override public void addInvalidatingType(JSType type) {
checkState(!type.isUnionType());
invalidatingTypes.add(type);
}
@Override public StaticScope<JSType> getRootScope() { return null; }
@Override public StaticScope<JSType> getFunctionScope(Node node) {
return null;
}
@Override public JSType getType(
StaticScope<JSType> scope, Node node, String prop) {
if (node.getJSType() == null) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return node.getJSType();
}
@Override public boolean isInvalidatingType(JSType type) {
if (type == null || invalidatingTypes.contains(type) ||
type.isUnknownType() /* unresolved types */) {
return true;
}
ObjectType objType = ObjectType.cast(type);
return objType != null && !objType.hasReferenceName();
}
@Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) {
type = type.restrictByNotNullOrUndefined();
if (type.isUnionType()) {
Set<JSType> types = Sets.newHashSet(type);
for (JSType alt : type.toMaybeUnionType().getAlternates()) {
types.addAll(getTypesToSkipForTypeNonUnion(type));
}
return ImmutableSet.copyOf(types);
} else if (type.isEnumElementType()) {
return getTypesToSkipForType(
type
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
return referencedObjType == null ? null :
referencedObjType.getImplicitPrototype();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, Node propertyNode) {
return referencedObjType == null ? true :
referencedObjType.defineProperty(
propertyName, type, inferred, propertyNode);
}
@Override
public boolean removeProperty(String name) {
return referencedObjType == null ? false :
referencedObjType.removeProperty(name);
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyTypeDeclared(propertyName);
}
@Override
public Node getPropertyNode(String propertyName) {
return referencedObjType == null ? null :
referencedObjType.getPropertyNode(propertyName);
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyTypeInferred(propertyName);
}
@Override
public boolean isPropertyInExterns(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyInExterns(propertyName);
}
@Override
public int getPropertiesCount() {
return referencedObjType == null ? 0 :
referencedObjType.getPropertiesCount();
}
@Override
protected void collectPropertyNames(Set<String> props) {
if (referencedObjType != null) {
referencedObjType.collectPropertyNames(props);
}
}
@Override
public JSType findPropertyType(String propertyName) {
return referencedType.findPropertyType(propertyName);
}
@Override
public JSType getPropertyType(String propertyName) {
return referencedObjType == null ?
getNativeType(JSTypeNative.UNKNOWN_TYPE) :
referencedObjType.getPropertyType(propertyName);
}
@Override
public JSDocInfo getJSDocInfo() {
return referencedType.getJSDocInfo();
}
@Override
public void setJSDocInfo(JSDocInfo info) {
if (referencedObjType != null) {
referencedObjType.setJSDocInfo(info);
}
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return referencedObjType == null ? null :
referencedObjType.getOwnPropertyJSDocInfo(propertyName);
}
@
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderShallowInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnionType(this);
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this); // for circularly defined types.
boolean changed = false;
ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder();
for (JSType alternate : alternates) {
JSType newAlternate = alternate.resolve(t, scope);
changed |= (alternate != newAlternate);
resolvedTypes.add(alternate);
}
if (changed) {
Collection<JSType> newAlternates = resolvedTypes.build();
Preconditions.checkState(
newAlternates.hashCode() == this.hashcode);
alternates = newAlternates;
}
return this;
}
@Override
public String toDebugHashCodeString() {
List<String> hashCodes = Lists.newArrayList();
for (JSType a : alternates) {
hashCodes.add(a.toDebugHashCodeString());
}
return "{(" + Joiner.on(",").join(hashCodes) + ")}";
}
@Override
public boolean setValidator(Predicate<JSType> validator) {
for (JSType a : alternates) {
a.setValidator(validator);
}
return true;
}
@Override
public JSType collapseUnion() {
JSType currentValue = null;
ObjectType currentCommonSuper = null;
for (JSType a : alternates) {
if (a.isUnknownType()) {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
ObjectType obj = a.toObjectType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
BOOLEAN_TYPE,
BOOLEAN_OBJECT_TYPE,
BOOLEAN_OBJECT_FUNCTION_TYPE,
/**
* A checked unknown type is a type that we know something about,
* but we're not really sure what we know about it.
*
* Examples of checked unknown types include:
* <code>
* if (x) { // x is unknown
* alert(x); // x is checked unknown
* }
* </code>
*
* <code>
* /* @param {SomeForwardDeclaredType} x /
* function f(x) {
* // x is checked unknown. We know it's some type, but the type
* // has not been included in this binary.
* }
* </code>
*
* This is useful for missing property warnings, where we don't
* want to emit warnings on things that have been checked.
*/
CHECKED_UNKNOWN_TYPE,
DATE_TYPE,
DATE_FUNCTION_TYPE,
ERROR_FUNCTION_TYPE,
ERROR_TYPE,
EVAL_ERROR_FUNCTION_TYPE,
EVAL_ERROR_TYPE,
FUNCTION_FUNCTION_TYPE,
FUNCTION_INSTANCE_TYPE, // equivalent to U2U_CONSTRUCTOR_TYPE
FUNCTION_PROTOTYPE,
NULL_TYPE,
NUMBER_TYPE,
NUMBER_OBJECT_TYPE,
NUMBER_OBJECT_FUNCTION_TYPE,
OBJECT_TYPE,
OBJECT_FUNCTION_TYPE,
OBJECT_PROTOTYPE,
RANGE_ERROR_FUNCTION_TYPE,
RANGE_ERROR_TYPE,
REFERENCE_ERROR_FUNCTION_TYPE,
REFERENCE_ERROR_TYPE,
REGEXP_TYPE,
REGEXP_FUNCTION_TYPE,
STRING_OBJECT_TYPE,
STRING_OBJECT_FUNCTION_TYPE,
STRING_TYPE,
SYNTAX_ERROR_FUNCTION_TYPE,
SYNTAX_ERROR_TYPE,
TYPE_ERROR_FUNCTION_TYPE,
TYPE_ERROR_TYPE,
UNKNOWN_TYPE,
URI_ERROR_FUNCTION_TYPE,
URI_ERROR_TYPE,
VOID_TYPE,
// Commonly used types
TOP_LEVEL_PROTOTYPE,
STRING_VALUE_OR_OBJECT_TYPE,
NUMBER_VALUE_OR_OBJECT_TYPE,
ALL_TYPE,
NO_TYPE,
NO_OBJECT_TYPE,
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>iserScopeKnowingConditionOutcome(Node condition,
FlowScope blindScope, boolean outcome) {
return firstLink.getPreciserScopeKnowingConditionOutcome(
condition, blindScope, outcome);
}
/**
* Delegates the calculation of the preciser scope to the next link.
* If there is no next link, returns the blind scope.
*/
protected FlowScope nextPreciserScopeKnowingConditionOutcome(Node condition,
FlowScope blindScope, boolean outcome) {
return nextLink != null ? nextLink.getPreciserScopeKnowingConditionOutcome(
condition, blindScope, outcome) : blindScope;
}
/**
* Returns the type of a node in the given scope if the node corresponds to a
* name whose type is capable of being refined.
* @return The current type of the node if it can be refined, null otherwise.
*/
protected JSType getTypeIfRefinable(Node node, FlowScope scope) {
switch (node.getType()) {
case Token.NAME:
StaticSlot<JSType> nameVar = scope.getSlot(node.getString());
if (nameVar != null) {
JSType nameVarType = nameVar.getType();
if (nameVarType == null) {
nameVarType = node.getJSType();
}
return nameVarType;
}
return null;
case Token.GETPROP:
String qualifiedName = node.getQualifiedName();
if (qualifiedName == null) {
return null;
}
StaticSlot<JSType> propVar = scope.getSlot(qualifiedName);
JSType propVarType = null;
if (propVar != null) {
propVarType = propVar.getType();
}
if (propVarType == null) {
propVarType = node.getJSType();
}
if (propVarType == null) {
propVarType = getNativeType(UNKNOWN_TYPE);
}
return propVarType;
}
return null;
}
/**
* Declares a refined type in {@code scope} for the name represented by
* {@code node}. It must be possible to refine the type of the given node in
* the given scope, as determined by {@link #getTypeIfRefinable}.
*/
protected void declare
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>NameInScope(FlowScope scope, Node node, JSType type) {
switch (node.getType()) {
case Token.NAME:
scope.inferSlotType(node.getString(), type);
break;
case Token.GETPROP:
String qualifiedName = node.getQualifiedName();
Preconditions.checkNotNull(qualifiedName);
JSType origType = node.getJSType();
origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType;
scope.inferQualifiedSlot(node, qualifiedName, origType, type);
break;
case Token.THIS:
// "this" references aren't currently modeled in the CFG.
break;
default:
throw new IllegalArgumentException("Node cannot be refined. \n" +
node.toStringTree());
}
}
/**
* @see #getRestrictedWithoutUndefined(JSType)
*/
private final Visitor<JSType> restrictUndefinedVisitor =
new Visitor<JSType>() {
@Override
public JSType caseEnumElementType(EnumElementType enumElementType) {
JSType type = enumElementType.getPrimitiveType().visit(this);
if (type != null && enumElementType.getPrimitiveType().equals(type)) {
return enumElementType;
} else {
return type;
}
}
@Override
public JSType caseAllType() {
return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE,
STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE);
}
@Override
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
@Override
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
@Override
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
@Override
public JSType caseFunctionType(FunctionType type) {
return type;
}
@Override
public JSType caseNullType() {
return getNativeType(NULL_TYPE);
}
@Override
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
@Override
public JSType caseObjectType(ObjectType type) {
return type;
}
@Override
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
}
@Override
public JSType caseUnionType(UnionType type) {
return type.getRestrictedUnion(getNativeType(VOID_TYPE));
}
@Override
public JSType caseUnknownType() {
return getNativeType(UNKNOWN_TYPE);
}
@Override
public JSType caseVoidType() {
return null;
}
@Override
public JSType caseParameterizedType(ParameterizedType type) {
return caseObjectType(type);
}
@Override
public JSType caseTemplateType(TemplateType templateType) {
return caseObjectType(templateType);
}
};
/**
* @see #getRestrictedWithoutNull(JSType)
*/
private final Visitor<JSType> restrictNullVisitor =
new Visitor<JSType>() {
@Override
public JSType caseEnumElementType(EnumElementType enumElementType) {
JSType type = enumElementType.getPrimitiveType().visit(this);
if (type != null && enumElementType.getPrimitiveType().equals(type)) {
return enumElementType;
} else {
return type;
}
}
@Override
public JSType caseAllType() {
return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE,
STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE);
}
@Override
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
@Override
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
@Override
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
@Override
public JSType caseFunctionType(FunctionType type) {
return type;
}
@Override
public JSType caseNullType() {
return null;
}
@Override
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
@Override
public JSType caseObjectType(ObjectType type) {
return type;
}
@Override
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
}
@Override
public JSType caseUnionType(UnionType type) {
return type.getRestrictedUnion(getNativeType(NULL_TYPE));
}
@Override
public JSType caseUnknownType() {
return
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> getNativeType(UNKNOWN_TYPE);
}
@Override
public JSType caseVoidType() {
return getNativeType(VOID_TYPE);
}
@Override
public JSType caseParameterizedType(ParameterizedType type) {
return caseObjectType(type);
}
@Override
public JSType caseTemplateType(TemplateType templateType) {
return caseObjectType(templateType);
}
};
/**
* A class common to all visitors that need to restrict the type based on
* {@code typeof}-like conditions.
*/
abstract class RestrictByTypeOfResultVisitor
implements Visitor<JSType> {
/**
* Abstracts away the similarities between visiting the unknown type and the
* all type.
* @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE}
* @return the restricted type
* @see #caseAllType
* @see #caseUnknownType
*/
protected abstract JSType caseTopType(JSType topType);
@Override
public JSType caseAllType() {
return caseTopType(getNativeType(ALL_TYPE));
}
@Override
public JSType caseUnknownType() {
return caseTopType(getNativeType(UNKNOWN_TYPE));
}
@Override
public JSType caseUnionType(UnionType type) {
JSType restricted = null;
for (JSType alternate : type.getAlternates()) {
JSType restrictedAlternate = alternate.visit(this);
if (restrictedAlternate != null) {
if (restricted == null) {
restricted = restrictedAlternate;
} else {
restricted = restrictedAlternate.getLeastSupertype(restricted);
}
}
}
return restricted;
}
@Override
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
@Override
public JSType caseEnumElementType(EnumElementType enumElementType) {
// NOTE(nicksantos): This is a white lie. Suppose we have:
// /** @enum {string|number} */ var MyEnum = ...;
// if (goog.isNumber(myEnumInstance)) {
// /* what is myEnumInstance here? */
// }
// There is no type that represents {MyEnum - string}. What we really
// need is a notion of "enum subtyping",
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>number"</td></tr>
* <tr><td>{@code string}</td><td>"string"</td></tr>
* <tr><td>{@code Object} (which doesn't implement [[Call]])</td>
* <td>"object"</td></tr>
* <tr><td>{@code Object} (which implements [[Call]])</td>
* <td>"function"</td></tr>
* </table>
* @param type the type to restrict
* @param value A value known to be equal or not equal to the result of the
* {@code typeof} operation
* @param resultEqualsValue {@code true} if the {@code typeOf} result is known
* to equal {@code value}; {@code false} if it is known <em>not</em> to
* equal {@code value}
* @return the restricted type or null if no version of the type matches the
* restriction
*/
JSType getRestrictedByTypeOfResult(JSType type, String value,
boolean resultEqualsValue) {
if (type == null) {
if (resultEqualsValue) {
JSType result = getNativeTypeForTypeOf(value);
return result == null ? getNativeType(UNKNOWN_TYPE) : result;
} else {
return null;
}
}
return type.visit(
new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue));
}
JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
/**
* If we definitely know what a type is based on the typeof result,
* return it. Otherwise, return null.
*
* The typeof operation in JS is poorly defined, and this function works
* for both the native typeof and goog.typeOf. It should not be made public,
* because its semantics are informally defined, and would be wrong in
* the general case.
*/
private JSType getNativeTypeForTypeOf(String value) {
if (value.equals("number")) {
return getNativeType(NUMBER_TYPE);
} else if (value.equals("boolean")) {
return getNativeType(BOOLEAN_TYPE);
} else if (value.equals("string")) {
return getNativeType(STRING_TYPE);
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> are duplicates of
// one another.
int currentIndex = 0;
Iterator<JSType> it = alternates.iterator();
while (it.hasNext()) {
JSType current = it.next();
// Unknown and NoResolved types may just be names that haven't
// been resolved yet. So keep these in the union, and just use
// equality checking for simple de-duping.
if (alternate.isUnknownType() ||
current.isUnknownType() ||
alternate.isNoResolvedType() ||
current.isNoResolvedType() ||
alternate.hasAnyTemplate() ||
current.hasAnyTemplate()) {
if (alternate.isEquivalentTo(current)) {
// Alternate is unnecessary.
return this;
}
} else {
if (alternate.isSubtype(current)) {
// Alternate is unnecessary.
return this;
} else if (current.isSubtype(alternate)) {
// Alternate makes current obsolete
it.remove();
if (currentIndex == functionTypePosition) {
functionTypePosition = -1;
} else if (currentIndex < functionTypePosition) {
functionTypePosition--;
currentIndex--;
}
}
}
currentIndex++;
}
if (alternate.isFunctionType()) {
// See the comments on functionTypePosition above.
Preconditions.checkState(functionTypePosition == -1);
functionTypePosition = alternates.size();
}
alternates.add(alternate);
result = null; // invalidate the memoized result
}
} else {
result = null;
}
return this;
}
/**
* Reduce the alternates into a non-union type.
* If the alternates can't be accurately represented with a non-union
* type, return null.
*/
private JSType reduceAlternatesWithoutUnion() {
if (isAllType) {
return registry.getNativeType(ALL_TYPE);
} else if (isNativeUnknownType) {
if (areAllUnknownsChecked) {
return registry.getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
return registry.getNativeType(UNKNOWN_TYPE);
}
} else {
int size = alternates.size();
if (size > maxUnionSize) {
return registry.getNativeType(UNKNOWN_TYPE);
} else
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>());
}
}
return false;
}
/**
* If this is equal to a NamedType object, its hashCode must be equal
* to the hashCode of the NamedType object.
*/
@Override
public int hashCode() {
if (hasReferenceName()) {
return getReferenceName().hashCode();
} else {
return super.hashCode();
}
}
@Override
String toStringHelper(boolean forAnnotations) {
return forAnnotations ?
primitiveType.toString() :
(getReferenceName() + ".<" + primitiveType + ">");
}
@Override
public String getReferenceName() {
return name;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtypeHelper(this, that)) {
return true;
} else {
return primitiveType.isSubtype(that);
}
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseEnumElementType(this);
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, Node propertyNode) {
// nothing
return true;
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return primitiveObjectType == null ?
false : primitiveObjectType.isPropertyTypeDeclared(propertyName);
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return primitiveObjectType == null ?
false : primitiveObjectType.isPropertyTypeInferred(propertyName);
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public int getPropertiesCount() {
return primitiveObjectType == null ?
0 : primitiveObjectType.getPropertiesCount();
}
@Override
void collectPropertyNames(Set<String> props) {
if (primitiveObjectType != null) {
primitiveObjectType.collectPropertyNames(props);
}
}
@Override
public JSType findPropertyType(String propertyName) {
return primitiveType.findPropertyType(propertyName);
}
@Override
public JSType getPropertyType(String propertyName) {
return primitiveObjectType == null ?
getNativeType(JSTypeNative.UNKNOWN_TYPE) :
primitiveObjectType.getPropertyType(propertyName);
}
@Override
public boolean hasProperty
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
// The subclass method might write its var_args as individual
// arguments.
if (currentParam.getNext() != null && newParam.isVarArgs()) {
newParam.setVarArgs(false);
newParam.setOptionalArg(true);
}
} else {
warnedAboutArgList |= addParameter(
paramBuilder,
typeRegistry.getNativeType(UNKNOWN_TYPE),
warnedAboutArgList,
codingConvention.isOptionalParameter(currentParam) ||
oldParamsListHitOptArgs,
codingConvention.isVarArgsParameter(currentParam));
}
}
// Clone any remaining params that aren't in the function literal,
// but make them optional.
while (oldParams.hasNext()) {
paramBuilder.newOptionalParameterFromNode(oldParams.next());
}
parametersNode = paramBuilder.build();
}
return this;
}
/**
* Infer the return type from JSDocInfo.
*/
FunctionTypeBuilder inferReturnType(@Nullable JSDocInfo info) {
if (info != null && info.hasReturnType()) {
returnType = info.getReturnType().evaluate(scope, typeRegistry);
returnTypeInferred = false;
}
return this;
}
/**
* Infer the role of the function (whether it's a constructor or interface)
* and what it inherits from in JSDocInfo.
*/
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
if (info != null) {
isConstructor = info.isConstructor();
isInterface = info.isInterface();
// base type
if (info.hasBaseType()) {
if (isConstructor) {
JSType maybeBaseType =
info.getBaseType().evaluate(scope, typeRegistry);
if (maybeBaseType != null &&
maybeBaseType.setValidator(new ExtendedTypeValidator())) {
baseType = (ObjectType) maybeBaseType;
}
} else {
reportWarning(EXTENDS_WITHOUT_TYPEDEF, fnName);
}
}
// implemented interfaces
if (isConstructor || isInterface) {
implementedInterfaces = Lists.newArrayList();
for (JSTypeExpression t : info.getImplementedInterfaces()) {
JSType maybeInterType = t.evaluate(scope, typeRegistry);
if (maybeInterType != null &&
maybeInterType.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> the parameter types from the list of argument names and
* the doc info.
*/
FunctionTypeBuilder inferParameterTypes(@Nullable Node argsParent,
@Nullable JSDocInfo info) {
if (argsParent == null) {
if (info == null) {
return this;
} else {
return inferParameterTypes(info);
}
}
// arguments
Node oldParameterType = null;
if (parametersNode != null) {
oldParameterType = parametersNode.getFirstChild();
}
FunctionParamBuilder builder = new FunctionParamBuilder(typeRegistry);
boolean warnedAboutArgList = false;
Set<String> allJsDocParams = (info == null) ?
Sets.<String>newHashSet() :
Sets.newHashSet(info.getParameterNames());
boolean foundTemplateType = false;
boolean isVarArgs = false;
for (Node arg : argsParent.children()) {
String argumentName = arg.getString();
allJsDocParams.remove(argumentName);
// type from JSDocInfo
JSType parameterType = null;
boolean isOptionalParam = isOptionalParameter(arg, info);
isVarArgs = isVarArgsParameter(arg, info);
if (info != null && info.hasParameterType(argumentName)) {
parameterType =
info.getParameterType(argumentName).evaluate(scope, typeRegistry);
} else if (oldParameterType != null &&
oldParameterType.getJSType() != null) {
parameterType = oldParameterType.getJSType();
isOptionalParam = oldParameterType.isOptionalArg();
isVarArgs = oldParameterType.isVarArgs();
} else {
parameterType = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
warnedAboutArgList |= addParameter(
builder, parameterType, warnedAboutArgList,
isOptionalParam,
isVarArgs);
if (oldParameterType != null) {
oldParameterType = oldParameterType.getNext();
}
}
// Copy over any old parameters that aren't in the param list.
if (!isVarArgs) {
while (oldParameterType != null && !isVarArgs) {
builder.newParameterFromNode(oldParameterType);
oldParameterType = oldParameterType.getNext();
}
}
for (String inexistentName : allJsDocParams) {
reportWarning(IN
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>Warning(VAR_ARGS_MUST_BE_LAST);
emittedWarning = true;
}
} else if (isVarArgs) {
if (!builder.addVarArgs(paramType) && !warnedAboutArgList) {
reportWarning(VAR_ARGS_MUST_BE_LAST);
emittedWarning = true;
}
} else {
if (!builder.addRequiredParams(paramType) && !warnedAboutArgList) {
// An optional parameter was seen and this argument is not an optional
// or var arg so it is an error.
if (builder.hasVarArgs()) {
reportWarning(VAR_ARGS_MUST_BE_LAST);
} else {
reportWarning(OPTIONAL_ARG_AT_END);
}
emittedWarning = true;
}
}
return emittedWarning;
}
/**
* Builds the function type, and puts it in the registry.
*/
FunctionType buildAndRegister() {
if (returnType == null) {
// Infer return types.
// We need to be extremely conservative about this, because of two
// competing needs.
// 1) If we infer the return type of f too widely, then we won't be able
// to assign f to other functions.
// 2) If we infer the return type of f too narrowly, then we won't be
// able to override f in subclasses.
// So we only infer in cases where the user doesn't expect to write
// @return annotations--when it's very obvious that the function returns
// nothing.
if (!contents.mayHaveNonEmptyReturns() &&
!contents.mayHaveSingleThrow() &&
!contents.mayBeFromExterns()) {
returnType = typeRegistry.getNativeType(VOID_TYPE);
returnTypeInferred = true;
}
}
if (returnType == null) {
returnType = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
if (parametersNode == null) {
throw new IllegalStateException(
"All Function types must have params and a return type");
}
FunctionType fnType;
if (isConstructor) {
fnType = getOrCreateConstructor();
} else if (isInterface) {
fnType = typeRegistry.createInterfaceType(
fnName, contents.getSourceNode());
if (
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> ObjectType classA = googAFunction.getInstanceType();
assertEquals(NATIVE_PROPERTIES_COUNT + 1, classA.getPropertiesCount());
checkObjectType(classA, "m1", NUMBER_TYPE);
}
public void testAddingMethodsPrototypeIdiomAndObjectLiteralSimpleNamespace()
throws Exception {
Node js1Node = parseAndTypeCheck(
"/** @constructor */function A() {}" +
"A.prototype = {m1: 5, m2: true}");
ObjectType instanceType = getInstanceType(js1Node);
assertEquals(NATIVE_PROPERTIES_COUNT + 2,
instanceType.getPropertiesCount());
checkObjectType(instanceType, "m1", NUMBER_TYPE);
checkObjectType(instanceType, "m2", BOOLEAN_TYPE);
}
public void testDontAddMethodsIfNoConstructor()
throws Exception {
Node js1Node = parseAndTypeCheck(
"function A() {}" +
"A.prototype = {m1: 5, m2: true}");
JSType functionAType = js1Node.getFirstChild().getJSType();
assertEquals("function (): undefined", functionAType.toString());
assertEquals(UNKNOWN_TYPE,
U2U_FUNCTION_TYPE.getPropertyType("m1"));
assertEquals(UNKNOWN_TYPE,
U2U_FUNCTION_TYPE.getPropertyType("m2"));
}
public void testFunctionAssignement() throws Exception {
testTypes("/**" +
"* @param {string} ph0" +
"* @param {string} ph1" +
"* @return {string}" +
"*/" +
"function MSG_CALENDAR_ACCESS_ERROR(ph0, ph1) {return ''}" +
"/** @type {Function} */" +
"var MSG_CALENDAR_ADD_ERROR = MSG_CALENDAR_ACCESS_ERROR;");
}
public void testAddMethodsPrototypeTwoWays() throws Exception {
Node js1Node = parseAndTypeCheck(
"/** @constructor */function A() {}" +
"A.prototype = {m1: 5, m2: true};" +
"A.prototype.m3 = 'third property!';");
ObjectType instanceType = getInstanceType(js1Node);
assertEquals("A", instanceType.toString());
assertEquals(NATIVE_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>) {
this.resolveMode = mode;
}
ResolveMode getResolveMode() {
return resolveMode;
}
public ErrorReporter getErrorReporter() {
return reporter;
}
public boolean shouldTolerateUndefinedValues() {
return tolerateUndefinedValues;
}
/**
* Reset to run the TypeCheck pass.
*/
public void resetForTypeCheck() {
typesIndexedByProperty.clear();
eachRefTypeIndexedByProperty.clear();
initializeBuiltInTypes();
namesToTypes.clear();
namespaces.clear();
initializeRegistry();
}
private void initializeBuiltInTypes() {
// These locals shouldn't be all caps.
BooleanType BOOLEAN_TYPE = new BooleanType(this);
registerNativeType(JSTypeNative.BOOLEAN_TYPE, BOOLEAN_TYPE);
NullType NULL_TYPE = new NullType(this);
registerNativeType(JSTypeNative.NULL_TYPE, NULL_TYPE);
NumberType NUMBER_TYPE = new NumberType(this);
registerNativeType(JSTypeNative.NUMBER_TYPE, NUMBER_TYPE);
StringType STRING_TYPE = new StringType(this);
registerNativeType(JSTypeNative.STRING_TYPE, STRING_TYPE);
UnknownType UNKNOWN_TYPE = new UnknownType(this, false);
registerNativeType(JSTypeNative.UNKNOWN_TYPE, UNKNOWN_TYPE);
registerNativeType(
JSTypeNative.CHECKED_UNKNOWN_TYPE, new UnknownType(this, true));
VoidType VOID_TYPE = new VoidType(this);
registerNativeType(JSTypeNative.VOID_TYPE, VOID_TYPE);
AllType ALL_TYPE = new AllType(this);
registerNativeType(JSTypeNative.ALL_TYPE, ALL_TYPE);
// Top Level Prototype (the One)
// The initializations of TOP_LEVEL_PROTOTYPE and OBJECT_FUNCTION_TYPE
// use each other's results, so at least one of them will get null
// instead of an actual type; however, this seems to be benign.
PrototypeObjectType TOP_LEVEL_PROTOTYPE =
new PrototypeObjectType(this, null, null, true);
registerNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE, TOP_LEVEL_PROTOTYPE);
// Object
FunctionType OBJECT_FUNCTION_TYPE =
new Function
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>Type(this, "Object", null,
createArrowType(createOptionalParameters(ALL_TYPE), UNKNOWN_TYPE),
null, null, true, true);
OBJECT_FUNCTION_TYPE.setPrototype(TOP_LEVEL_PROTOTYPE, null);
registerNativeType(JSTypeNative.OBJECT_FUNCTION_TYPE, OBJECT_FUNCTION_TYPE);
ObjectType OBJECT_TYPE = OBJECT_FUNCTION_TYPE.getInstanceType();
registerNativeType(JSTypeNative.OBJECT_TYPE, OBJECT_TYPE);
ObjectType OBJECT_PROTOTYPE = OBJECT_FUNCTION_TYPE.getPrototype();
registerNativeType(JSTypeNative.OBJECT_PROTOTYPE, OBJECT_PROTOTYPE);
// Function
FunctionType FUNCTION_FUNCTION_TYPE =
new FunctionType(this, "Function", null,
createArrowType(
createParametersWithVarArgs(ALL_TYPE), UNKNOWN_TYPE),
null, null, true, true);
FUNCTION_FUNCTION_TYPE.setPrototypeBasedOn(OBJECT_TYPE);
registerNativeType(
JSTypeNative.FUNCTION_FUNCTION_TYPE, FUNCTION_FUNCTION_TYPE);
ObjectType FUNCTION_PROTOTYPE = FUNCTION_FUNCTION_TYPE.getPrototype();
registerNativeType(JSTypeNative.FUNCTION_PROTOTYPE, FUNCTION_PROTOTYPE);
NoType NO_TYPE = new NoType(this);
registerNativeType(JSTypeNative.NO_TYPE, NO_TYPE);
NoObjectType NO_OBJECT_TYPE = new NoObjectType(this);
registerNativeType(JSTypeNative.NO_OBJECT_TYPE, NO_OBJECT_TYPE);
NoObjectType NO_RESOLVED_TYPE = new NoResolvedType(this);
registerNativeType(JSTypeNative.NO_RESOLVED_TYPE, NO_RESOLVED_TYPE);
// Array
FunctionType ARRAY_FUNCTION_TYPE =
new FunctionType(this, "Array", null,
createArrowType(createParametersWithVarArgs(ALL_TYPE), null),
null, null, true, true);
ARRAY_FUNCTION_TYPE.getInternalArrowType().returnType =
ARRAY_FUNCTION_TYPE.getInstanceType();
ObjectType arrayPrototype = ARRAY_FUNCTION_TYPE.getPrototype();
registerNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE, ARRAY_FUNCTION_TYPE);
ObjectType ARRAY_TYPE = ARRAY_FUNCTION_TYPE.getInstanceType();
registerNativeType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(JSTypeNative.ARRAY_TYPE, ARRAY_TYPE);
// Boolean
FunctionType BOOLEAN_OBJECT_FUNCTION_TYPE =
new FunctionType(this, "Boolean", null,
createArrowType(createParameters(false, ALL_TYPE), BOOLEAN_TYPE),
null, null, true, true);
ObjectType booleanPrototype = BOOLEAN_OBJECT_FUNCTION_TYPE.getPrototype();
registerNativeType(
JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE,
BOOLEAN_OBJECT_FUNCTION_TYPE);
ObjectType BOOLEAN_OBJECT_TYPE =
BOOLEAN_OBJECT_FUNCTION_TYPE.getInstanceType();
registerNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE, BOOLEAN_OBJECT_TYPE);
// Date
FunctionType DATE_FUNCTION_TYPE =
new FunctionType(this, "Date", null,
createArrowType(
createOptionalParameters(UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE,
UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE, UNKNOWN_TYPE),
STRING_TYPE),
null, null, true, true);
ObjectType datePrototype = DATE_FUNCTION_TYPE.getPrototype();
registerNativeType(JSTypeNative.DATE_FUNCTION_TYPE, DATE_FUNCTION_TYPE);
ObjectType DATE_TYPE = DATE_FUNCTION_TYPE.getInstanceType();
registerNativeType(JSTypeNative.DATE_TYPE, DATE_TYPE);
// Error
FunctionType ERROR_FUNCTION_TYPE = new ErrorFunctionType(this, "Error");
registerNativeType(JSTypeNative.ERROR_FUNCTION_TYPE, ERROR_FUNCTION_TYPE);
ObjectType ERROR_TYPE = ERROR_FUNCTION_TYPE.getInstanceType();
registerNativeType(JSTypeNative.ERROR_TYPE, ERROR_TYPE);
// EvalError
FunctionType EVAL_ERROR_FUNCTION_TYPE =
new ErrorFunctionType(this, "EvalError");
EVAL_ERROR_FUNCTION_TYPE.setPrototypeBasedOn(ERROR_TYPE);
registerNativeType(
JSTypeNative.EVAL_ERROR_FUNCTION_TYPE, EVAL_ERROR_FUNCTION_TYPE);
ObjectType EVAL_ERROR_TYPE = EVAL_ERROR_FUNCTION_TYPE.getInstanceType();
registerNativeType(JSTypeNative.EVAL_ERROR_TYPE, EVAL_ERROR_TYPE);
// RangeError
FunctionType RANGE_ERROR_FUNCTION_TYPE =
new ErrorFunctionType(this, "Range
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>,number)
JSType OBJECT_NUMBER_STRING =
createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE);
registerNativeType(JSTypeNative.OBJECT_NUMBER_STRING, OBJECT_NUMBER_STRING);
// (Object,string,number,boolean)
JSType OBJECT_NUMBER_STRING_BOOLEAN =
createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE);
registerNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN,
OBJECT_NUMBER_STRING_BOOLEAN);
// (string,number,boolean)
JSType NUMBER_STRING_BOOLEAN =
createUnionType(NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE);
registerNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN,
NUMBER_STRING_BOOLEAN);
// (string,number)
JSType NUMBER_STRING = createUnionType(NUMBER_TYPE, STRING_TYPE);
registerNativeType(JSTypeNative.NUMBER_STRING, NUMBER_STRING);
// Native object properties are filled in by externs...
// (String, string)
JSType STRING_VALUE_OR_OBJECT_TYPE =
createUnionType(STRING_OBJECT_TYPE, STRING_TYPE);
registerNativeType(
JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE, STRING_VALUE_OR_OBJECT_TYPE);
// (Number, number)
JSType NUMBER_VALUE_OR_OBJECT_TYPE =
createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE);
registerNativeType(
JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE);
// unknown function type, i.e. (?...) -> ?
FunctionType U2U_FUNCTION_TYPE =
createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE);
registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE);
// unknown constructor type, i.e. (?...) -> ? with the NoObject type
// as instance type
FunctionType U2U_CONSTRUCTOR_TYPE =
// This is equivalent to
// createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but,
// in addition, overrides getInstanceType() to return the NoObject type
// instead of a new anonymous object.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
new FunctionType(this, "Function", null,
createArrowType(
createParametersWithVarArgs(UNKNOWN_TYPE),
UNKNOWN_TYPE),
NO_OBJECT_TYPE, null, true, true) {
private static final long serialVersionUID = 1L;
@Override public FunctionType getConstructor() {
return registry.getNativeFunctionType(
JSTypeNative.FUNCTION_FUNCTION_TYPE);
}
};
// The U2U_CONSTRUCTOR is weird, because it's the supertype of its
// own constructor.
registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE);
registerNativeType(
JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE);
FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE);
U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE);
// least function type, i.e. (All...) -> NoType
FunctionType LEAST_FUNCTION_TYPE =
createNativeFunctionTypeWithVarArgs(NO_TYPE, ALL_TYPE);
registerNativeType(JSTypeNative.LEAST_FUNCTION_TYPE, LEAST_FUNCTION_TYPE);
// the 'this' object in the global scope
FunctionType GLOBAL_THIS_CTOR =
new FunctionType(this, "global this", null,
createArrowType(createParameters(false, ALL_TYPE), NUMBER_TYPE),
null, null, true, true);
ObjectType GLOBAL_THIS = GLOBAL_THIS_CTOR.getInstanceType();
registerNativeType(JSTypeNative.GLOBAL_THIS, GLOBAL_THIS);
// greatest function type, i.e. (NoType...) -> All
FunctionType GREATEST_FUNCTION_TYPE =
createNativeFunctionTypeWithVarArgs(ALL_TYPE, NO_TYPE);
registerNativeType(JSTypeNative.GREATEST_FUNCTION_TYPE,
GREATEST_FUNCTION_TYPE);
// Register the prototype property. See the comments below in
// registerPropertyOnType about the bootstrapping process.
registerPropertyOnType("prototype", OBJECT_FUNCTION_TYPE);
}
private void initializeRegistry() {
register(getNativeType(JSTypeNative.ARRAY_TYPE));
register(getNativeType(JSTypeNative
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> if (resolveMode == ResolveMode.LAZY_EXPRESSIONS) {
// If the type expression doesn't contain any names, just
// resolve it anyway.
boolean hasNames = hasTypeName(n);
if (hasNames) {
return new UnresolvedTypeExpression(this, n, sourceName);
}
}
return createFromTypeNodesInternal(n, sourceName, scope);
}
private boolean hasTypeName(Node n) {
if (n.getType() == Token.STRING) {
return true;
}
for (Node child = n.getFirstChild();
child != null; child = child.getNext()) {
if (hasTypeName(child)) {
return true;
}
}
return false;
}
/** @see #createFromTypeNodes(Node, String, StaticScope) */
private JSType createFromTypeNodesInternal(Node n, String sourceName,
StaticScope<JSType> scope) {
switch (n.getType()) {
case Token.LC: // Record type.
return createRecordTypeFromNodes(
n.getFirstChild(), sourceName, scope);
case Token.BANG: // Not nullable
return createFromTypeNodesInternal(
n.getFirstChild(), sourceName, scope)
.restrictByNotNullOrUndefined();
case Token.QMARK: // Nullable or unknown
Node firstChild = n.getFirstChild();
if (firstChild == null) {
return getNativeType(UNKNOWN_TYPE);
}
return createDefaultObjectUnion(
createFromTypeNodesInternal(
firstChild, sourceName, scope));
case Token.EQUALS: // Optional
return createOptionalType(
createFromTypeNodesInternal(
n.getFirstChild(), sourceName, scope));
case Token.ELLIPSIS: // Var args
return createOptionalType(
createFromTypeNodesInternal(
n.getFirstChild(), sourceName, scope));
case Token.STAR: // The AllType
return getNativeType(ALL_TYPE);
case Token.LB: // Array type
// TODO(nicksantos): Enforce membership restrictions on the Array.
return getNativeType(ARRAY_TYPE);
case Token.PIPE: // Union type
UnionTypeBuilder builder = new UnionTypeBuilder(this);
for (Node child = n.getFirstChild(); child != null;
child =
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> child.getNext()) {
builder.addAlternate(
createFromTypeNodesInternal(child, sourceName, scope));
}
return builder.build();
case Token.EMPTY: // When the return value of a function is not specified
return getNativeType(UNKNOWN_TYPE);
case Token.VOID: // Only allowed in the return value of a function.
return getNativeType(VOID_TYPE);
case Token.STRING:
JSType namedType = getType(scope, n.getString(), sourceName,
n.getLineno(), n.getCharno());
if (resolveMode != ResolveMode.LAZY_NAMES) {
namedType = namedType.resolveInternal(reporter, scope);
}
if ((namedType instanceof ObjectType) &&
!(nonNullableTypeNames.contains(n.getString()))) {
Node typeList = n.getFirstChild();
if (typeList != null &&
("Array".equals(n.getString()) ||
"Object".equals(n.getString()))) {
JSType parameterType =
createFromTypeNodesInternal(
typeList.getLastChild(), sourceName, scope);
namedType = new ParameterizedType(
this, (ObjectType) namedType, parameterType);
if (typeList.hasMoreThanOneChild()) {
JSType indexType =
createFromTypeNodesInternal(
typeList.getFirstChild(), sourceName, scope);
namedType = new IndexedType(
this, (ObjectType) namedType, indexType);
}
}
return createDefaultObjectUnion(namedType);
} else {
return namedType;
}
case Token.FUNCTION:
ObjectType thisType = null;
boolean isConstructor = false;
Node current = n.getFirstChild();
if (current.getType() == Token.THIS ||
current.getType() == Token.NEW) {
Node contextNode = current.getFirstChild();
thisType =
ObjectType.cast(
createFromTypeNodesInternal(
contextNode, sourceName, scope)
.restrictByNotNullOrUndefined());
if (thisType == null) {
reporter.warning(
ScriptRuntime.getMessage0(
current.getType() == Token.THIS ?
"msg.jsdoc.function.thisnotobject" :
"msg.jsdoc.function.newnotobject"),
sourceName,
contextNode.getLineno
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(), contextNode.getCharno());
}
isConstructor = current.getType() == Token.NEW;
current = current.getNext();
}
FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this);
if (current.getType() == Token.PARAM_LIST) {
Node args = current.getFirstChild();
for (Node arg = current.getFirstChild(); arg != null;
arg = arg.getNext()) {
if (arg.getType() == Token.ELLIPSIS) {
if (arg.getChildCount() == 0) {
paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE));
} else {
paramBuilder.addVarArgs(
createFromTypeNodesInternal(
arg.getFirstChild(), sourceName, scope));
}
} else {
JSType type = createFromTypeNodesInternal(
arg, sourceName, scope);
if (arg.getType() == Token.EQUALS) {
boolean addSuccess = paramBuilder.addOptionalParams(type);
if (!addSuccess) {
reporter.warning(
ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"),
sourceName, arg.getLineno(), arg.getCharno());
}
} else {
paramBuilder.addRequiredParams(type);
}
}
}
current = current.getNext();
}
JSType returnType =
createFromTypeNodesInternal(current, sourceName, scope);
return new FunctionBuilder(this)
.withParams(paramBuilder)
.withReturnType(returnType)
.withTypeOfThis(thisType)
.setIsConstructor(isConstructor)
.build();
}
throw new IllegalStateException(
"Unexpected node in type expression: " + n.toString());
}
/**
* Creates a RecordType from the nodes representing said record type.
* @param n The node with type info.
* @param sourceName The source file name.
* @param scope A scope for doing type name lookups.
*/
private JSType createRecordTypeFromNodes(Node n, String sourceName,
StaticScope<JSType> scope) {
RecordTypeBuilder builder = new RecordTypeBuilder(this);
// For each of the fields in the record type.
for (Node fieldTypeNode = n.getFirstChild();
fieldTypeNode != null;
fieldType
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>Node = fieldTypeNode.getNext()) {
// Get the property's name.
Node fieldNameNode = fieldTypeNode;
boolean hasType = false;
if (fieldTypeNode.getType() == Token.COLON) {
fieldNameNode = fieldTypeNode.getFirstChild();
hasType = true;
}
String fieldName = fieldNameNode.getString();
// TODO(user): Move this into the lexer/parser.
// Remove the string literal characters around a field name,
// if any.
if (fieldName.startsWith("'") || fieldName.startsWith("\"")) {
fieldName = fieldName.substring(1, fieldName.length() - 1);
}
// Get the property's type.
JSType fieldType = null;
if (hasType) {
// We have a declared type.
fieldType = createFromTypeNodesInternal(
fieldTypeNode.getLastChild(), sourceName, scope);
} else {
// Otherwise, the type is UNKNOWN.
fieldType = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
// Add the property to the record.
if (builder.addProperty(fieldName, fieldType, fieldNameNode) == null) {
// Duplicate field name, warning and skip
reporter.warning(
"Duplicate record field " + fieldName,
sourceName,
n.getLineno(), fieldNameNode.getCharno());
}
}
return builder.build();
}
/**
* Sets the template type name.
*/
public void setTemplateTypeNames(List<String> names) {
Preconditions.checkNotNull(names);
for (String name : names) {
templateTypes.put(name, new TemplateType(this, name));
}
}
/**
* Clears the template type name.
*/
public void clearTemplateTypeNames() {
templateTypes.clear();
}
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> arrow type from the complex
* {@link FunctionType} that models JavaScript's notion of functions.
*/
final class ArrowType extends JSType {
private static final long serialVersionUID = 1L;
final Node parameters;
JSType returnType;
// Whether the return type is inferred.
final boolean returnTypeInferred;
ArrowType(JSTypeRegistry registry, Node parameters,
JSType returnType) {
this(registry, parameters, returnType, false);
}
ArrowType(JSTypeRegistry registry, Node parameters,
JSType returnType, boolean returnTypeInferred) {
super(registry);
this.parameters = parameters == null ?
registry.createParametersWithVarArgs(getNativeType(UNKNOWN_TYPE)) :
parameters;
this.returnType = returnType == null ?
getNativeType(UNKNOWN_TYPE) : returnType;
this.returnTypeInferred = returnTypeInferred;
}
@Override
public boolean isSubtype(JSType other) {
if (!(other instanceof ArrowType)) {
return false;
}
ArrowType that = (ArrowType) other;
// This is described in Draft 2 of the ES4 spec,
// Section 3.4.7: Subtyping Function Types.
// this.returnType <: that.returnType (covariant)
if (!this.returnType.isSubtype(that.returnType)) {
return false;
}
// that.paramType[i] <: this.paramType[i] (contravariant)
//
// If this.paramType[i] is required,
// then that.paramType[i] is required.
//
// In theory, the "required-ness" should work in the other direction as
// well. In other words, if we have
//
// function f(number, number) {}
// function g(number) {}
//
// Then f *should* not be a subtype of g, and g *should* not be
// a subtype of f. But in practice, we do not implement it this way.
// We want to support the use case where you can pass g where f is
// expected, and pretend that g ignores the second argument.
// That way, you can have a single "no-op" function, and you don't have
// to create a new no-op function for every possible type signature.
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>JSTypeNative;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import com.google.javascript.rhino.jstype.ObjectType;
import com.google.javascript.rhino.jstype.RecordTypeBuilder;
import junit.framework.TestCase;
public abstract class BaseJSTypeTestCase extends TestCase {
protected JSTypeRegistry registry;
protected TestErrorReporter errorReporter;
protected JSType ALL_TYPE;
protected ObjectType NO_OBJECT_TYPE;
protected ObjectType NO_TYPE;
protected ObjectType NO_RESOLVED_TYPE;
protected JSType ARRAY_FUNCTION_TYPE;
protected ObjectType ARRAY_TYPE;
protected JSType BOOLEAN_OBJECT_FUNCTION_TYPE;
protected ObjectType BOOLEAN_OBJECT_TYPE;
protected JSType BOOLEAN_TYPE;
protected JSType CHECKED_UNKNOWN_TYPE;
protected JSType DATE_FUNCTION_TYPE;
protected ObjectType DATE_TYPE;
protected JSType ERROR_FUNCTION_TYPE;
protected ObjectType ERROR_TYPE;
protected JSType EVAL_ERROR_FUNCTION_TYPE;
protected ObjectType EVAL_ERROR_TYPE;
protected FunctionType FUNCTION_FUNCTION_TYPE;
protected FunctionType FUNCTION_INSTANCE_TYPE;
protected ObjectType FUNCTION_PROTOTYPE;
protected JSType GREATEST_FUNCTION_TYPE;
protected JSType LEAST_FUNCTION_TYPE;
protected JSType MATH_TYPE;
protected JSType NULL_TYPE;
protected JSType NUMBER_OBJECT_FUNCTION_TYPE;
protected ObjectType NUMBER_OBJECT_TYPE;
protected JSType NUMBER_STRING_BOOLEAN;
protected JSType NUMBER_TYPE;
protected FunctionType OBJECT_FUNCTION_TYPE;
protected JSType NULL_VOID;
protected JSType OBJECT_NUMBER_STRING;
protected JSType OBJECT_NUMBER_STRING_BOOLEAN;
protected JSType OBJECT_PROTOTYPE;
protected ObjectType OBJECT_TYPE;
protected JSType RANGE_ERROR_FUNCTION_TYPE;
protected ObjectType RANGE_ERROR_TYPE;
protected JSType REFERENCE_ERROR_FUNCTION_TYPE;
protected ObjectType REFERENCE_ERROR_TYPE;
protected JSType REGEXP_FUNCTION_TYPE;
protected ObjectType REGEXP_TYPE;
protected JSType STRING_OBJECT_FUNCTION_TYPE;
protected ObjectType STRING_OBJECT_TYPE;
protected JSType STRING_TYPE;
protected JSType SYNTAX_ERROR_FUNCTION_
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>TYPE;
protected ObjectType SYNTAX_ERROR_TYPE;
protected JSType TYPE_ERROR_FUNCTION_TYPE;
protected ObjectType TYPE_ERROR_TYPE;
protected FunctionType U2U_CONSTRUCTOR_TYPE;
protected FunctionType U2U_FUNCTION_TYPE;
protected ObjectType UNKNOWN_TYPE;
protected JSType URI_ERROR_FUNCTION_TYPE;
protected ObjectType URI_ERROR_TYPE;
protected JSType VOID_TYPE;
protected int NATIVE_PROPERTIES_COUNT;
@Override
protected void setUp() throws Exception {
super.setUp();
errorReporter = new TestErrorReporter(null, null);
registry = new JSTypeRegistry(errorReporter);
initTypes();
}
protected void initTypes() {
ALL_TYPE =
registry.getNativeType(JSTypeNative.ALL_TYPE);
NO_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE);
NO_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_TYPE);
NO_RESOLVED_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_RESOLVED_TYPE);
ARRAY_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE);
ARRAY_TYPE =
registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE);
BOOLEAN_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE);
BOOLEAN_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
BOOLEAN_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_TYPE);
CHECKED_UNKNOWN_TYPE =
registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
DATE_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE);
DATE_TYPE =
registry.getNativeObjectType(JSTypeNative.DATE_TYPE);
ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE);
ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.ERROR_TYPE);
EVAL_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE);
EVAL
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>ERROR_TYPE);
REGEXP_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.REGEXP_FUNCTION_TYPE);
REGEXP_TYPE =
registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE);
STRING_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE);
STRING_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE);
STRING_TYPE =
registry.getNativeType(JSTypeNative.STRING_TYPE);
SYNTAX_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE);
SYNTAX_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.SYNTAX_ERROR_TYPE);
TYPE_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.TYPE_ERROR_FUNCTION_TYPE);
TYPE_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.TYPE_ERROR_TYPE);
U2U_CONSTRUCTOR_TYPE =
registry.getNativeFunctionType(JSTypeNative.U2U_CONSTRUCTOR_TYPE);
U2U_FUNCTION_TYPE =
registry.getNativeFunctionType(JSTypeNative.U2U_FUNCTION_TYPE);
UNKNOWN_TYPE =
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
URI_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.URI_ERROR_FUNCTION_TYPE);
URI_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.URI_ERROR_TYPE);
VOID_TYPE =
registry.getNativeType(JSTypeNative.VOID_TYPE);
addNativeProperties(registry);
NATIVE_PROPERTIES_COUNT = OBJECT_TYPE.getPropertiesCount();
}
/** Adds a basic set of properties to the native types. */
public static void addNativeProperties(JSTypeRegistry registry) {
JSType booleanType = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE);
JSType numberType = registry.getNativeType(JSTypeNative.NUMBER_TYPE);
JSType stringType = registry.getNativeType(JSTypeNative.STRING_TYPE);
JSType unknownType = registry.getNativeType(JSTypeNative
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>.UNKNOWN_TYPE);
ObjectType objectType =
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
ObjectType arrayType =
registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE);
ObjectType dateType =
registry.getNativeObjectType(JSTypeNative.DATE_TYPE);
ObjectType regexpType =
registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE);
ObjectType booleanObjectType =
registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
ObjectType numberObjectType =
registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE);
ObjectType stringObjectType =
registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE);
ObjectType objectPrototype = registry
.getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, objectPrototype, "constructor", objectType);
addMethod(registry, objectPrototype, "toString", stringType);
addMethod(registry, objectPrototype, "toLocaleString", stringType);
addMethod(registry, objectPrototype, "valueOf", unknownType);
addMethod(registry, objectPrototype, "hasOwnProperty", booleanType);
addMethod(registry, objectPrototype, "isPrototypeOf", booleanType);
addMethod(registry, objectPrototype, "propertyIsEnumerable", booleanType);
ObjectType arrayPrototype = registry
.getNativeFunctionType(JSTypeNative.ARRAY_FUNCTION_TYPE)
.getPrototype();
addMethod(registry, arrayPrototype, "constructor", arrayType);
addMethod(registry, arrayPrototype, "toString", stringType);
addMethod(registry, arrayPrototype, "toLocaleString", stringType);
addMethod(registry, arrayPrototype, "concat", arrayType);
addMethod(registry, arrayPrototype, "join", stringType);
addMethod(registry, arrayPrototype, "pop", unknownType);
addMethod(registry, arrayPrototype, "push", numberType);
addMethod(registry, arrayPrototype, "reverse", arrayType);
addMethod(registry, arrayPrototype, "shift", unknownType);
addMethod(registry, arrayPrototype, "slice", arrayType);
addMethod(registry, arrayPrototype, "sort", arrayType);
addMethod(registry, arrayPrototype, "splice", arrayType);
addMethod(registry, arrayPrototype, "unshift", number
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>VOID:
n.setJSType(getNativeType(VOID_TYPE));
break;
case Token.STRING:
n.setJSType(getNativeType(STRING_TYPE));
break;
case Token.NUMBER:
n.setJSType(getNativeType(NUMBER_TYPE));
break;
case Token.TRUE:
case Token.FALSE:
n.setJSType(getNativeType(BOOLEAN_TYPE));
break;
case Token.REGEXP:
n.setJSType(getNativeType(REGEXP_TYPE));
break;
case Token.OBJECTLIT:
JSDocInfo info = n.getJSDocInfo();
if (info != null &&
info.getLendsName() != null) {
if (lentObjectLiterals == null) {
lentObjectLiterals = Lists.newArrayList();
}
lentObjectLiterals.add(n);
} else {
defineObjectLiteral(n);
}
break;
// NOTE(nicksantos): If we ever support Array tuples,
// we will need to put ARRAYLIT here as well.
}
}
private void defineObjectLiteral(Node objectLit) {
// Handle the @lends annotation.
JSType type = null;
JSDocInfo info = objectLit.getJSDocInfo();
if (info != null &&
info.getLendsName() != null) {
String lendsName = info.getLendsName();
Var lendsVar = scope.getVar(lendsName);
if (lendsVar == null) {
compiler.report(
JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName));
} else {
type = lendsVar.getType();
if (type == null) {
type = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) {
compiler.report(
JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT,
lendsName, type.toString()));
type = null;
} else {
objectLit.setJSType(type);
}
}
}
info = NodeUtil.getBestJSDocInfo(object
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>(sourceName, n, MULTIPLE_VAR_DEF));
}
for (Node name : n.children()) {
defineName(name, n, parent, name.getJSDocInfo());
}
} else {
Node name = n.getFirstChild();
defineName(name, n, parent,
(info != null) ? info : name.getJSDocInfo());
}
}
/**
* Defines a function literal.
*/
void defineFunctionLiteral(Node n, Node parent) {
assertDefinitionNode(n, Token.FUNCTION);
// Determine the name and JSDocInfo and l-value for the function.
// Any of these may be null.
Node lValue = NodeUtil.getBestLValue(n);
JSDocInfo info = NodeUtil.getBestJSDocInfo(n);
String functionName = NodeUtil.getBestLValueName(lValue);
FunctionType functionType =
createFunctionTypeFromNodes(n, functionName, info, lValue);
// Assigning the function type to the function node
setDeferredType(n, functionType);
// Declare this symbol in the current scope iff it's a function
// declaration. Otherwise, the declaration will happen in other
// code paths.
if (NodeUtil.isFunctionDeclaration(n)) {
defineSlot(n.getFirstChild(), n, functionType);
}
}
/**
* Defines a variable based on the {@link Token#NAME} node passed.
* @param name The {@link Token#NAME} node.
* @param var The parent of the {@code name} node, which must be a
* {@link Token#VAR} node.
* @param parent {@code var}'s parent.
* @param info the {@link JSDocInfo} information relating to this
* {@code name} node.
*/
private void defineName(Node name, Node var, Node parent, JSDocInfo info) {
Node value = name.getFirstChild();
// variable's type
JSType type = getDeclaredType(sourceName, info, name, value);
if (type == null) {
// The variable's type will be inferred.
type = name.isFromExterns() ?
getNativeType(UNKNOWN_TYPE) : null;
}
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>();
String propName = n.getLastChild().getString();
String ownerName = stub.ownerName;
boolean isExtern = stub.isExtern;
if (scope.isDeclared(qName, false)) {
continue;
}
// If we see a stub property, make sure to register this property
// in the type registry.
ObjectType ownerType = getObjectSlot(ownerName);
ObjectType unknownType = typeRegistry.getNativeObjectType(UNKNOWN_TYPE);
defineSlot(n, parent, unknownType, true);
if (ownerType != null &&
(isExtern || ownerType.isFunctionPrototypeType())) {
// If this is a stub for a prototype, just declare it
// as an unknown type. These are seen often in externs.
ownerType.defineInferredProperty(
propName, unknownType, n);
} else {
typeRegistry.registerPropertyOnType(
propName, ownerType == null ? unknownType : ownerType);
}
}
}
/**
* Collects all declared properties in a function, and
* resolves them relative to the global scope.
*/
private final class CollectProperties
extends AbstractShallowStatementCallback {
private final ObjectType thisType;
CollectProperties(ObjectType thisType) {
this.thisType = thisType;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isExprResult()) {
Node child = n.getFirstChild();
switch (child.getType()) {
case Token.ASSIGN:
maybeCollectMember(t, child.getFirstChild(), child,
child.getLastChild());
break;
case Token.GETPROP:
maybeCollectMember(t, child, child, null);
break;
}
}
}
private void maybeCollectMember(NodeTraversal t,
Node member, Node nodeWithJsDocInfo, @Nullable Node value) {
JSDocInfo info = nodeWithJsDocInfo.getJSDocInfo();
// Do nothing if there is no JSDoc type info, or
// if the node is not a member expression, or
// if the member expression is not of the form: this.someProperty.
if (info == null ||
!member.isGetProp() ||
!member.getFirstChild().isThis()) {
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> JSDocInfo info) {
if (info == null || !info.hasTypedefType()) {
return;
}
String typedef = candidate.getQualifiedName();
if (typedef == null) {
return;
}
// TODO(nicksantos|user): This is a terrible, terrible hack
// to bail out on recursive typedefs. We'll eventually need
// to handle these properly.
typeRegistry.declareType(typedef, getNativeType(UNKNOWN_TYPE));
JSType realType = info.getTypedefType().evaluate(scope, typeRegistry);
if (realType == null) {
compiler.report(
JSError.make(
t.getSourceName(), candidate, MALFORMED_TYPEDEF, typedef));
}
typeRegistry.overwriteDeclaredType(typedef, realType);
if (candidate.isGetProp()) {
defineSlot(candidate, candidate.getParent(),
getNativeType(NO_TYPE), false);
}
}
} // end GlobalScopeBuilder
/**
* A shallow traversal of a local scope to find all arguments and
* local variables.
*/
private final class LocalScopeBuilder extends AbstractScopeBuilder {
/**
* @param scope The scope that we're building.
*/
private LocalScopeBuilder(Scope scope) {
super(scope);
}
/**
* Traverse the scope root and build it.
*/
void build() {
NodeTraversal.traverse(compiler, scope.getRootNode(), this);
AstFunctionContents contents =
getFunctionAnalysisResults(scope.getRootNode());
if (contents != null) {
for (String varName : contents.getEscapedVarNames()) {
Var v = scope.getVar(varName);
Preconditions.checkState(v.getScope() == scope);
v.markEscaped();
}
}
}
/**
* Visit a node in a local scope, and add any local variables or catch
* parameters into the local symbol table.
*
* @param t The node traversal.
* @param n The node being visited.
* @param parent The parent of n
*/
@Override public void visit(NodeTraversal t, Node n, Node parent) {
if (n == scope.getRootNode()) return;
if (n.isParamList() && parent == scope.getRootNode())
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS> this function. It is only relevant for
* constructors and may be {@code null}.
*/
private List<FunctionType> subTypes;
/**
* The template type name. May be {@code null}.
*/
private final ImmutableList<String> templateTypeNames;
/** Creates an instance for a function that might be a constructor. */
FunctionType(JSTypeRegistry registry, String name, Node source,
ArrowType arrowType, ObjectType typeOfThis,
ImmutableList<String> templateTypeNames,
boolean isConstructor, boolean nativeType) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE),
nativeType);
setPrettyPrint(true);
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
Preconditions.checkNotNull(arrowType);
this.source = source;
this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY;
if (isConstructor) {
this.typeOfThis = typeOfThis != null ?
typeOfThis : new InstanceObjectType(registry, this, nativeType);
} else {
this.typeOfThis = typeOfThis != null ?
typeOfThis :
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
}
this.call = arrowType;
this.templateTypeNames = templateTypeNames != null
? templateTypeNames : ImmutableList.<String>of();
}
/** Creates an instance for a function that is an interface. */
private FunctionType(JSTypeRegistry registry, String name, Node source) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE));
setPrettyPrint(true);
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
Preconditions.checkArgument(name != null);
this.source = source;
this.call = new ArrowType(registry, new Node(Token.PARAM_LIST), null);
this.kind = Kind.INTERFACE;
this.typeOfThis = new InstanceObjectType(registry, this);
this.templateTypeNames = ImmutableList.of();
}
/** Creates an instance for a function that is an interface. */
static FunctionType forInterface(
JSTypeRegistry registry, String name, Node source) {
return new FunctionType(registry, name
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>
}
}
return Integer.MAX_VALUE;
}
public JSType getReturnType() {
return call.returnType;
}
public boolean isReturnTypeInferred() {
return call.returnTypeInferred;
}
/** Gets the internal arrow type. For use by subclasses only. */
ArrowType getInternalArrowType() {
return call;
}
@Override
public Property getSlot(String name) {
if ("prototype".equals(name)) {
// Lazy initialization of the prototype field.
getPrototype();
return prototypeSlot;
} else {
return super.getSlot(name);
}
}
/**
* Includes the prototype iff someone has created it. We do not want
* to expose the prototype for ordinary functions.
*/
@Override
public Set<String> getOwnPropertyNames() {
if (prototypeSlot == null) {
return super.getOwnPropertyNames();
} else {
Set<String> names = Sets.newHashSet("prototype");
names.addAll(super.getOwnPropertyNames());
return names;
}
}
/**
* Gets the {@code prototype} property of this function type. This is
* equivalent to {@code (ObjectType) getPropertyType("prototype")}.
*/
public ObjectType getPrototype() {
// lazy initialization of the prototype field
if (prototypeSlot == null) {
String refName = getReferenceName();
if (refName == null) {
// Someone is trying to access the prototype of a structural function.
// We don't want to give real properties to this prototype, because
// then it would propagate to all structural functions.
setPrototypeNoCheck(
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE),
null);
} else {
setPrototype(
new PrototypeObjectType(
registry,
this.getReferenceName() + ".prototype",
registry.getNativeObjectType(OBJECT_TYPE),
isNativeObjectType()),
null);
}
}
return (ObjectType) prototypeSlot.getType();
}
/**
* Sets the prototype, creating the prototype object from the given
* base type.
* @param baseType The base type.
*/
public void setPrototypeBasedOn(ObjectType baseType) {
setPrototypeBasedOn(baseType, null);
}
void setPrototypeBasedOn(ObjectType baseType, Node propertyNode)
Closure, 167
<FILEB>
<CHANGES>
left, leftType, leftIsRefineable? merged.typeA : null,
right, rightType, rightIsRefineable? merged.typeB : null);
<CHANGEE>
<CHANGES>
left, leftType, leftIsRefineable? restrictedLeftType : null,
right, rightType, rightIsRefineable? restrictedRightType : null);
<CHANGEE>
<CHANGES>
if (restrictedType!= null && restrictedType!= originalType) {
<CHANGEE>
<CHANGES>
Node left, JSType originalLeftType, JSType restrictedLeftType,
Node right, JSType originalRightType, JSType restrictedRightType) {
<CHANGEE>
<CHANGES>
restrictedLeftType!= null && restrictedLeftType!= originalLeftType;
<CHANGEE>
<CHANGES>
restrictedRightType!= null && restrictedRightType!= originalRightType;
<CHANGEE>
<CHANGES>
return maybeRestrictName(
blindScope, name, type,
type.getRestrictedTypeGivenToBooleanOutcome(outcome));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outcome && this == getNativeType(JSTypeNative.UNKNOWN_TYPE)) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
<CHANGEE>
<FILEE>
<FILEB>
leftIsRefineable = false;
leftType = left.getJSType();
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
}
// merged types
TypePair merged = merging.apply(new TypePair(leftType, rightType));
// creating new scope
if (merged != null) {
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, merged.typeA,
right, rightIsRefineable, merged.typeB);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrNotShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
// left type
JSType leftType = getTypeIfRefinable(left, blindScope);
boolean leftIsRefineable;
if (leftType != null) {
leftIsRefineable = true;
} else {
leftIsRefineable = false;
}
// right type
JSType rightType = getTypeIfRefinable(right, blindScope);
boolean rightIsRefineable;
if (rightType != null) {
rightIsRefineable = true;
} else {
rightIsRefineable = false;
rightType = right.getJSType();
blindScope = firstPreciserScopeKnowingConditionOutcome(
right, blindScope, condition);
}
if (condition) {
JSType restrictedRightType = (rightType == null) ? null :
rightType.getRestrictedTypeGivenToBooleanOutcome(condition);
// creating new scope
return maybeRestrictTwoNames(
blindScope,
<CHANGES>
left, leftIsRefineable, restrictedLeftType,
right, rightIsRefineable, restrictedRightType);
<CHANGEE>
}
return blindScope;
}
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right,
FlowScope blindScope, boolean condition) {
FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome(
left, blindScope, !condition);
Static<SCANS>variant of the other,
// then we'll treat them as covariant (see comment above).
other.typeOfThis.isSubtype(this.typeOfThis) ||
this.typeOfThis.isSubtype(other.typeOfThis);
return treatThisTypesAsCovariant && this.call.isSubtype(other.call);
}
return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that);
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseFunctionType(this);
}
/**
* Gets the type of instance of this function.
* @throws IllegalStateException if this function is not a constructor
* (see {@link #isConstructor()}).
*/
public ObjectType getInstanceType() {
Preconditions.checkState(hasInstanceType());
return typeOfThis;
}
/**
* Sets the instance type. This should only be used for special
* native types.
*/
void setInstanceType(ObjectType instanceType) {
typeOfThis = instanceType;
}
/**
* Returns whether this function type has an instance type.
*/
public boolean hasInstanceType() {
return isConstructor() || isInterface();
}
/**
* Gets the type of {@code this} in this function.
*/
@Override
public ObjectType getTypeOfThis() {
return typeOfThis.isNoObjectType() ?
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE) : typeOfThis;
}
/**
* Gets the source node or null if this is an unknown function.
*/
public Node getSource() {
return source;
}
/**
* Sets the source node.
*/
public void setSource(Node source) {
if (prototypeSlot != null) {
// NOTE(bashir): On one hand when source is null we want to drop any
// references to old nodes retained in prototypeSlot. On the other hand
// we cannot simply drop prototypeSlot, so we retain all information
// except the propertyNode for which we use an approximation! These
// details mostly matter in hot-swap passes.
if (source == null || prototypeSlot.getNode() == null) {
prototypeSlot = new Property(prototypeSlot.getName(),
prototypeSlot.getType(), prototypeSlot.isTypeInferred(), source);
}